diff --git a/WorkshopProject.prj b/DevOps.prj
similarity index 100%
rename from WorkshopProject.prj
rename to DevOps.prj
diff --git a/README.md b/README.md
index 7849f93..dfd68bc 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-[](https://github.com/simkaryote/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml)
-[](https://simkaryote.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/tests/)
-[](https://simkaryote.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/coverage/)
+[](https://github.com/ChezJe/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml)
+[](https://ChezJe.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/tests/)
+[](https://ChezJe.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/coverage/)
# Generating Tests for Your MATLAB® Code Workshop
diff --git a/buildfile.m b/buildfile.m
index 820d3a6..20f86c2 100644
--- a/buildfile.m
+++ b/buildfile.m
@@ -1,22 +1,20 @@
function plan = buildfile
-
import matlab.buildtool.tasks.*
+% Extract tasks from local functions
plan = buildplan(localfunctions);
-% Set default task
-plan.DefaultTasks = "test";
-
-
% CodeIssues task
-plan("check") = CodeIssuesTask();
+plan("check") = CodeIssuesTask(Results=["results/codeissues.sarif"; ...
+ "results/codeissues.mat"]);
% Test task
tTask = TestTask("tests", ...
SourceFiles = "code", ...
IncludeSubfolders = true,...
- TestResults = fullfile("results","tests","index.html"), ...
- Dependencies = "check");
+ TestResults = fullfile("results","tests","index.html"),...
+ RunOnlyImpactedTests=true);
+
tTaskWithMatlabTest = tTask.addCodeCoverage( ...
fullfile("results","coverage","index.html"), ...
MetricLevel = "condition"); % Note: Change MetricLevel to "statement"
@@ -26,4 +24,52 @@
% Clean task
plan("clean") = CleanTask();
+% Define dependencies
+plan("compile").Dependencies = "test";
+plan("test").Dependencies = "generateSimFun";
+plan("generateSimFun").Dependencies = "check";
+
+% Define inputs and outputs
+proj = currentProject;
+plan("generateSimFun").Inputs = fullfile(proj.RootFolder,"code","*.sbproj");
+plan("generateSimFun").Outputs = fullfile(proj.RootFolder,"code","*.mat");
+plan("test").Inputs = fullfile(proj.RootFolder,"code","*");
+plan("compile").Inputs = fullfile(proj.RootFolder,"code",["*.mat","*.mlapp","graystyle.m"]);
+plan("compile").Outputs = fullfile(proj.RootFolder,"WebAppArchive");
+
+% Set default task
+plan.DefaultTasks = "compile";
+
+
+end
+
+function generateSimFunTask(~)
+ % Generate SimFunction and associated MAT file for app to run
+ generateSimFun();
+end
+
+function compileTask(~)
+ % Compile App into Web App
+
+ proj = currentProject;
+ rootFolder = proj.RootFolder; % Get the root folder of the project
+
+ imgFiles = dir(fullfile(rootFolder,"code","images","*.*"));
+ imgFiles = string({imgFiles.name}');
+ imgFiles = fullfile(rootFolder,"code","images",imgFiles(~matches(imgFiles,[".",".."])));
+ codeFiles = dir(fullfile(rootFolder,"code","*.m"));
+ codeFiles = string({codeFiles.name}');
+ codeFiles = fullfile(rootFolder,"code",setdiff(codeFiles,"generateSimFun.m"));
+
+ MATfilename = dir(fullfile(rootFolder,"code","*.mat"));
+ MATfilename = fullfile(rootFolder,"code",MATfilename.name);
+ load(MATfilename,"dependenciesSimFun");
+
+ appDependencies = [MATfilename; dependenciesSimFun; ...
+ codeFiles; imgFiles];
+ appfilename = fullfile(rootFolder,"code","TMDDApp.mlapp");
+
+ compiler.build.webAppArchive(appfilename,...
+ AdditionalFiles=appDependencies,OutputDir="WebAppArchive");
+
end
diff --git a/code/ConcTimecourseView.m b/code/ConcTimecourseView.m
new file mode 100644
index 0000000..a341078
--- /dev/null
+++ b/code/ConcTimecourseView.m
@@ -0,0 +1,75 @@
+classdef ConcTimecourseView < handle
+
+ properties ( Access = private )
+ Model
+ Axes
+
+ ConcColors = [0.30,0.75,0.93;...
+ 0.86,0.55,0.41;...
+ 0.91,0.73,0.42]; % colors to plot concentrations
+ FontName = "Helvetica";
+ end
+
+ properties ( SetAccess=private, GetAccess={?tTMDDApp} )
+ % line handles
+ lhDrug
+ lhReceptor
+ lhComplex
+
+ end
+
+ properties( Access = private )
+ DataListener % listener
+ end
+
+ methods
+ function obj = ConcTimecourseView(parent, model)
+
+ arguments
+ parent
+ model (1,1) SimulationModel
+ end
+
+ ax = uiaxes(parent);
+ graystyle(ax);
+ xlabel(ax, "Time (hours)", 'FontName',obj.FontName);
+ ylabel(ax, "Concentrations (nanomole/liter)",'FontName',obj.FontName);
+
+ obj.lhDrug = plot(ax, NaN, NaN, '-','Linewidth',2,'Color',obj.ConcColors(1,:));
+ hold(ax,'on');
+ obj.lhReceptor = plot(ax, NaN, NaN, '-','Linewidth',2,'Color',obj.ConcColors(2,:));
+ obj.lhComplex= plot(ax, NaN, NaN, '-','Linewidth',2,'Color',obj.ConcColors(3,:));
+ hold(ax,'off');
+ lh = legend(ax,{'Drug','Receptor','Complex'},'FontName',obj.FontName);
+ lh.Box = 'off';
+
+ % instantiate listener
+ dataListener = event.listener( model, 'DataChanged', ...
+ @obj.update );
+
+ % store listeners
+ obj.DataListener = dataListener;
+
+ % save objects
+ obj.Model = model;
+ obj.Axes = ax;
+
+ end % constructor
+
+
+ end % public methods
+
+ methods ( Access = private )
+
+ function update(obj,~,~)
+ t = obj.Model.SimDataTable;
+
+ set(obj.lhDrug,'XData',t.Time, 'YData',t.Drug);
+ set(obj.lhReceptor,'XData',t.Time, 'YData',t.Receptor);
+ set(obj.lhComplex,'XData',t.Time, 'YData',t.Complex);
+
+ end % update
+
+ end % private method
+end % class
+
diff --git a/code/LampView.m b/code/LampView.m
new file mode 100644
index 0000000..c457ec1
--- /dev/null
+++ b/code/LampView.m
@@ -0,0 +1,70 @@
+classdef LampView < handle
+
+ properties ( Dependent )
+ IsOn (1,1) logical
+ end
+
+ properties
+ LampColorSucess = [0.47, 0.67, 0.19] % color of lamp if RO between thresholds after day 1
+ LampColorFailure = [0.85, 0.33, 0.10] % color of lamp if RO not between thresholds after day 1
+ end
+
+ properties ( SetAccess=private, GetAccess={?tTMDDApp} )
+ LampObj
+ end
+
+ properties ( Access=private )
+ Model
+ end
+
+ properties( Access = private )
+ DataListener % listener
+ end
+
+ methods
+ function obj = LampView(parent,model)
+
+ lampObj = uilamp(parent);
+ lampObj.Tooltip = compose("Target occupancy does not remain\n between thresholds");
+ lampObj.Color = obj.LampColorFailure;
+
+ % instantiate listener
+ dataListener = event.listener( model, 'DataChanged', ...
+ @obj.update );
+
+ % store listeners
+ obj.DataListener = dataListener;
+
+ obj.LampObj = lampObj;
+ obj.Model = model;
+
+ end % constructor
+
+ function set.IsOn(obj, value)
+ % color lamp according to whether or not RO remains between thresholds after day 1
+ if value
+ obj.LampObj.Color = obj.LampColorSucess;
+ obj.LampObj.Tooltip = compose("Target occupancy remains\n between thresholds");
+ else
+ obj.LampObj.Color = obj.LampColorFailure;
+ obj.LampObj.Tooltip = compose("Target occupancy does not remain\n between thresholds");
+ end
+
+ obj.LampObj.UserData = value;
+
+ end % set.IsOn
+
+ function value = get.IsOn(obj)
+ value = obj.LampObj.UserData;
+ end % get.IsOn
+
+ end % public methods
+
+ methods ( Access = private )
+
+ function update(obj,~,~)
+ obj.IsOn = obj.Model.ROIsBetweenThresholds;
+ end % update
+
+ end % private method
+end
\ No newline at end of file
diff --git a/code/NCAView.m b/code/NCAView.m
new file mode 100644
index 0000000..9f05d46
--- /dev/null
+++ b/code/NCAView.m
@@ -0,0 +1,87 @@
+classdef NCAView < handle
+
+ properties ( Access = private )
+ Model
+ NCApanel
+ GridLayout
+
+ end
+
+ properties ( SetAccess=private, GetAccess={?tTMDDApp} )
+ NCAtable
+ end
+
+ properties ( Access = public )
+ FontName (1,1) string = "Helvetica"
+ NCAoptions % options for NCA calculations
+ ConcentrationColumnName (1,1) string = "Complex"
+ end
+
+ properties( Access = private )
+ DataListener % listener
+ end
+
+ methods
+ function obj = NCAView(parent, model)
+
+ arguments
+ parent
+ model (1,1) SimulationModel
+ end
+
+ ncapanel = uipanel(parent);
+ ncapanel.Title = "NCA parameters for bound target ('" + ...
+ obj.ConcentrationColumnName + "')";
+ ncapanel.BackgroundColor = [1 1 1];
+ ncapanel.FontName = obj.FontName;
+ ncapanel.BorderType = 'none';
+
+ % Create GridLayout
+ gl = uigridlayout(ncapanel);
+ gl.ColumnWidth = {'1x'};
+ gl.RowHeight = {'1x'};
+ gl.Padding = [0 0 0 0];
+ gl.BackgroundColor = [1 1 1];
+
+ % Create NCAtable
+ ncat = uitable(gl);
+
+ % save NCA options
+ opt = sbioncaoptions;
+ opt.concentrationColumnName = obj.ConcentrationColumnName;
+ opt.timeColumnName = 'Time';
+ opt.IVDoseColumnName = 'Dose';
+
+ % instantiate listener
+ dataListener = event.listener( model, 'DataChanged', ...
+ @obj.update );
+
+ % store listeners
+ obj.DataListener = dataListener;
+
+ % save objects
+ obj.Model = model;
+ obj.NCAoptions = opt;
+ obj.NCApanel = ncapanel;
+ obj.GridLayout = gl;
+ obj.NCAtable = ncat;
+
+ end % constructor
+
+
+ end % public methods
+
+ methods ( Access = private )
+
+ function update(obj,~,~)
+
+ % compute NCA parameters and display them in table
+ ncaParameters = sbionca(obj.Model.SimDataTable, obj.NCAoptions);
+ obj.NCAtable.ColumnName = ncaParameters.Properties.VariableNames(2:end);
+ obj.NCAtable.Data = ncaParameters(:,2:end);
+
+ end % update
+
+ end % private method
+end % class
+
diff --git a/code/ROTimecourseView.m b/code/ROTimecourseView.m
new file mode 100644
index 0000000..84d9e50
--- /dev/null
+++ b/code/ROTimecourseView.m
@@ -0,0 +1,77 @@
+classdef ROTimecourseView < handle
+
+ properties ( Access = private )
+ Model
+ Axes
+
+ ThresholdStyle = {'Color','r','Linewidth',2,'LineStyle','--',...
+ 'FontWeight','bold','LabelVerticalAlignment','middle'}; % style for threshold lines
+ end
+
+ properties ( GetAccess = {?tTMDDApp} )
+ % line handles
+ lhRO
+ end
+
+ properties ( Access = public )
+ ConcColors = [0.30,0.75,0.93;...
+ 0.86,0.55,0.41;...
+ 0.91,0.73,0.42]; % colors to plot concentrations
+ ROColors = [0.30,0.75,0.93];
+ FontName = "Helvetica";
+ end
+
+ properties( Access = private )
+ DataListener % listener
+ end
+
+ methods
+ function obj = ROTimecourseView(parent, model)
+
+ arguments
+ parent
+ model (1,1) SimulationModel
+ end
+
+ ax = uiaxes(parent);
+ graystyle(ax);
+ xlabel(ax, "Time (hours)", 'FontName',obj.FontName);
+ ylabel(ax, "RO (%)",'FontName',obj.FontName);
+
+ obj.lhRO = plot(ax, NaN, NaN, 'Color', obj.ROColors,'Linewidth',2);
+ yline(ax,model.ThresholdValues(1), '--','efficacy','FontName',obj.FontName,obj.ThresholdStyle{:});
+ yline(ax,model.ThresholdValues(2), '--','safety','FontName',obj.FontName,obj.ThresholdStyle{:});
+
+
+ % set limits
+ xlim(ax,'auto');
+ ylim(ax,[-5, 105]);
+
+ % instantiate listener
+ dataListener = event.listener( model, 'DataChanged', ...
+ @obj.update );
+
+ % store listeners
+ obj.DataListener = dataListener;
+
+ % save objects
+ obj.Model = model;
+ obj.Axes = ax;
+
+ end % constructor
+
+
+ end % public methods
+
+ methods ( Access = private )
+
+ function update(obj,~,~)
+ t = obj.Model.SimDataTable;
+
+ set(obj.lhRO,'XData',t.Time, 'YData',100*t.RO);
+
+ end % update
+
+ end % private method
+end % class
+
diff --git a/code/SimulationModel.m b/code/SimulationModel.m
new file mode 100644
index 0000000..d4b4811
--- /dev/null
+++ b/code/SimulationModel.m
@@ -0,0 +1,93 @@
+classdef SimulationModel < handle
+% Class to simulate the TMDD model
+
+ properties ( SetAccess = private )
+ DoseTable % daily dose to apply to simulate
+ SimFun % exported SimFunction
+
+ SimData
+ SimDataTable
+
+ ThresholdValues = [20, 80] % threshold values
+
+ end
+
+ properties
+ % original values for resetting
+ Amount0 (1,1) double
+ Duration0 (1,1) double
+ Kon0 (1,1) double
+ Kel0 (1,1) double
+ Kdeg0 (1,1) double
+ Interval0 (1,1) double
+ ROIsBetweenThresholds (1,1) logical
+ end
+
+ events ( NotifyAccess = private )
+ DataChanged
+ end
+
+ methods
+
+ function obj = SimulationModel()
+ % load Simfunction and dosing information
+ load('simFunction_Dose.mat', 'simFun', 'doseTable');
+ obj.SimFun = simFun;
+ obj.DoseTable = doseTable;
+
+
+ % save original values to allow for resetting
+ obj.Kel0 = obj.SimFun.Parameters.Value(1);
+ obj.Kon0 = obj.SimFun.Parameters.Value(2);
+ obj.Kdeg0 = obj.SimFun.Parameters.Value(3);
+ obj.Duration0 = 119;
+ obj.Interval0 = obj.DoseTable.Interval;
+ obj.Amount0 = obj.DoseTable.Amount;
+
+ end % constructor
+
+ end
+
+ methods
+
+ function simulate(obj, parameters)
+
+ arguments
+ obj
+ parameters (1,:) double
+ end
+
+ cellpar = num2cell(parameters);
+ [kel, kon, kdeg,stopTime, amount, interval] = deal(cellpar{:});
+ obj.DoseTable.Amount = amount;
+ obj.DoseTable.Interval = interval;
+
+ sd = obj.SimFun([kel, kon, kdeg], stopTime, obj.DoseTable);
+ t = array2table([sd.Time, sd.Data], 'VariableNames',[{'Time'}; sd.DataNames]);
+ t.Properties.VariableUnits = [{'hours'}; cellfun(@(x) x.Units, sd.DataInfo, 'UniformOutput', false)];
+
+ % add dosing information to table to compute NCA parameters
+ t.Dose = NaN(height(t),1);
+ dosingTimes = interval*(0:stopTime/interval);
+ t.Dose(ismember(t.Time, dosingTimes)) = amount;
+ idxNotIncreasing = diff(t.Time)<=0; % remove duplicates
+ t(idxNotIncreasing,:) = [];
+
+ % logical value to check whether or not RO remains between thresholds after day 1
+ aboveThreshold1 = all(t.RO(t.Time >= 24) >= obj.ThresholdValues(1)/100);
+ belowThreshold2 = all(t.RO(t.Time >= 24) <= obj.ThresholdValues(2)/100);
+ obj.ROIsBetweenThresholds = aboveThreshold1 && belowThreshold2;
+
+ obj.SimData = sd;
+ obj.SimDataTable = t;
+
+ notify( obj, 'DataChanged' );
+
+ end % simulate
+
+
+ end % public methods
+
+
+end % classdef
+
diff --git a/code/TMDD.sbproj b/code/TMDD.sbproj
new file mode 100644
index 0000000..be0de33
Binary files /dev/null and b/code/TMDD.sbproj differ
diff --git a/code/TMDDApp.mlapp b/code/TMDDApp.mlapp
new file mode 100644
index 0000000..97c89dc
Binary files /dev/null and b/code/TMDDApp.mlapp differ
diff --git a/code/generateSimFun.m b/code/generateSimFun.m
new file mode 100644
index 0000000..6dbc5b8
--- /dev/null
+++ b/code/generateSimFun.m
@@ -0,0 +1,44 @@
+function MATfilename = generateSimFun(MATfilename)
+
+arguments
+ MATfilename = "simFunction_Dose.mat"
+end
+
+% if only a file name without folder name is provided, make sure the MAT
+% file is saved in the same directory as generateSimFun.m
+if ~contains(MATfilename,filesep)
+ fullpath = mfilename('fullpath');
+ folder = fileparts(fullpath);
+ MATfilename = fullfile(folder,MATfilename);
+end
+
+% Load the SimBiology project into the workspace
+s = sbioloadproject("TMDD.sbproj",'m1');
+modelObj = s.m1;
+doseObj = modelObj.getdose('Daily Dose');
+basevariantObj = modelObj.getvariant('Estimated values');
+
+% Use hours for dose timing and convert any day-based interval to hours
+oldTimeUnit = doseObj.TimeUnits;
+doseObj.TimeUnits = 'hour';
+doseObj.Interval = sbiounitcalculator(oldTimeUnit, ...
+ doseObj.TimeUnits, doseObj.Interval);
+
+% Increase the number of repeat doses for long simulations
+doseObj.RepeatCount = 200;
+
+% Save dose table for simulation
+doseTable = doseObj.getTable();
+
+% Create a simulation function
+simFun = modelObj.createSimFunction({'kel','kon','kdeg'}, ...
+ {'Drug','Receptor','Complex','RO'}, doseObj.TargetName, basevariantObj);
+
+% Compile the simulation function for faster execution
+simFun.accelerate();
+dependenciesSimFun = simFun.DependentFiles';
+
+% Create MAT file
+save(MATfilename,"simFun","doseTable","dependenciesSimFun");
+
+end
diff --git a/code/graystyle.m b/code/graystyle.m
new file mode 100644
index 0000000..0dfce90
--- /dev/null
+++ b/code/graystyle.m
@@ -0,0 +1,50 @@
+function graystyle(axh)
+
+% Set figure background to white
+fh = axh.Parent;
+if isprop(fh,'Color')
+ fh.Color = 'w';
+elseif isprop(fh,'BackgroundColor')
+ fh.BackgroundColor = 'w';
+end
+
+
+% Set axes background and edges to gray
+axh.Color = ones(1,3)*0.9;
+axh.XColor = axh.Color;
+axh.YColor = axh.Color;
+axh.ZColor = axh.Color;
+
+% Set grid to white
+axh.GridColor = 'white';
+axh.GridAlpha = 1; %0.4;
+axh.Layer = 'bottom';
+grid(axh,'on');
+
+% Set ticks and box
+axh.TickDir = 'out';
+axh.TickLength = [0.005 0.012];
+axh.Box = 'off';
+
+% Set TickLabels color to gray
+axh.XAxis.TickLabelFormat = '\\color\[rgb\]\{0.5,0.5,0.5\} %g';
+axh.YAxis.TickLabelFormat = axh.XAxis.TickLabelFormat;
+axh.ZAxis.TickLabelFormat = axh.XAxis.TickLabelFormat;
+
+% Set label colors to same colors as TickLabels
+axh.XLabel.Color = ones(1,3)*0.4;
+axh.YLabel.Color = axh.XLabel.Color;
+axh.ZLabel.Color = axh.XLabel.Color;
+
+% Set legend
+lh = legend(axh,'hide');
+lh.EdgeColor = [1 1 1];
+
+
+% Set Linewidth for children
+if ~isempty(axh.Children)
+ set(axh.Children, 'LineWidth',1.5)
+end
+
+end
+
\ No newline at end of file
diff --git a/code/images/Run_24.png b/code/images/Run_24.png
new file mode 100644
index 0000000..550f4b5
Binary files /dev/null and b/code/images/Run_24.png differ
diff --git a/code/images/diagram.png b/code/images/diagram.png
new file mode 100644
index 0000000..3daaa68
Binary files /dev/null and b/code/images/diagram.png differ
diff --git a/code/images/diagram.svg b/code/images/diagram.svg
new file mode 100644
index 0000000..eb2836d
--- /dev/null
+++ b/code/images/diagram.svg
@@ -0,0 +1,265 @@
+
+
+
diff --git a/code/isLeapYear.m b/code/isLeapYear.m
deleted file mode 100644
index 64c0a93..0000000
--- a/code/isLeapYear.m
+++ /dev/null
@@ -1,32 +0,0 @@
-function isLeap = isLeapYear(year)
-%ISLEAPYEAR Determine if a year is a leap year
-%
-% isLeap = isLeapYear(year) returns true if the year is a leap year
-% - Leap years are divisible by 400, or divisible by 4 and not 100
-%
-% Example:
-% isLeapYear(2000) % returns true
-% isLeapYear(2024) % returns true
-% isLeapYear(2025) % returns false
-
-arguments
- year (1,1) {mustBeInteger, mustBePositive}
-end
-
-% Set up logical comparisons for clarity
-isDivBy400 = mod(year,400) == 0;
-isDivBy100 = mod(year,100) == 0;
-isDivBy4 = mod(year, 4) == 0;
-
-% Check for leap year
-if isDivBy400
- isLeap = true;
-elseif isDivBy4
- isLeap = true;
-elseif isDivBy100
- isLeap = false;
-else
- isLeap = false;
-end
-
-end
diff --git a/code/rockPaperScissors.m b/code/rockPaperScissors.m
deleted file mode 100644
index 8e8f89a..0000000
--- a/code/rockPaperScissors.m
+++ /dev/null
@@ -1,37 +0,0 @@
-function result = rockPaperScissors(p1, p2)
-% rockPaperScissors Determine the winner of a Rock-Paper-Scissors game
-%
-% result = rockPaperScissors(p1, p2) returns a string indicating the outcome:
-% - "Tie" if both players choose the same
-% - "Player 1 wins" if player 1 beats player 2
-% - "Player 2 wins" if player 2 beats player 1
-% - Error if either input is invalid
-%
-% Valid inputs: "rock", "paper", "scissors" (case-insensitive)
-%
-% Example:
-% rockPaperScissors("rock", "scissors") % returns "Player 1 wins"
-% rockPaperScissors("paper", "rock") % returns "Player 1 wins"
-% rockPaperScissors("scissors", "scissors") % returns "Tie"
-
-arguments
- p1 (1,1) string {mustBeMember(p1,["rock","paper","scissors"])}
- p2 (1,1) string {mustBeMember(p2,["rock","paper","scissors"])}
-end
-
-rockVsScissors = p1 == "rock" && p2 == "scissors";
-scissorsVsPaper = p1 == "scissors" && p2 == "paper";
-paperVsRock = p1 == "paper" && p2 == "rock";
-
-% Compare hands
-if p1 == p2
- result = "Tie";
-
-elseif rockVsScissors || scissorsVsPaper || paperVsRock
- result = "Player 1 wins";
-
-else
- result = "Player 2 wins";
-end
-
-end
diff --git a/code/simFunction_Dose.mat b/code/simFunction_Dose.mat
new file mode 100644
index 0000000..c9b533b
Binary files /dev/null and b/code/simFunction_Dose.mat differ
diff --git a/code/simpleSort.m b/code/simpleSort.m
deleted file mode 100644
index 5f1a423..0000000
--- a/code/simpleSort.m
+++ /dev/null
@@ -1,34 +0,0 @@
-function sortedArray = simpleSort(inputVector)
-%SIMPLESORT Uses a Bubble Sort algorithm to sort an array of numbers in
-% ascending order
-%
-% sortedArray = simpleSort(array) returns a new array with the same
-% elements as the input array, sorted in ascending order
-%
-% Example:
-% simpleSort([3, 1, 4, 1, 5]) % returns [1 1 3 4 5]
-%
-% Input must be a numeric vector.
-
-arguments
- inputVector {mustBeNumeric,mustBeVector(inputVector,"allow-all-empties")}
-end
-
-% Copy the array to avoid modifying the input
-sortedArray = inputVector;
-
-n = length(sortedArray);
-
-% Bubble Sort algorithm
-for ii = 1:n-1
- for jj = 1:n-ii
- if sortedArray(jj) > sortedArray(jj+1)
- % Swap elements
- temp = sortedArray(jj);
- sortedArray(jj) = sortedArray(jj+1);
- sortedArray(jj+1) = temp;
- end
- end
-end
-
-end
diff --git a/images/image_0.svg b/images/image_0.svg
deleted file mode 100644
index f2c8c7d..0000000
--- a/images/image_0.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_1.svg b/images/image_1.svg
deleted file mode 100644
index 569a860..0000000
--- a/images/image_1.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_10.svg b/images/image_10.svg
deleted file mode 100644
index 4c4fe59..0000000
--- a/images/image_10.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_11.svg b/images/image_11.svg
deleted file mode 100644
index 2114a01..0000000
--- a/images/image_11.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_12.png b/images/image_12.png
deleted file mode 100644
index dba759c..0000000
Binary files a/images/image_12.png and /dev/null differ
diff --git a/images/image_13.png b/images/image_13.png
deleted file mode 100644
index 440f297..0000000
Binary files a/images/image_13.png and /dev/null differ
diff --git a/images/image_14.png b/images/image_14.png
deleted file mode 100644
index 7383aa7..0000000
Binary files a/images/image_14.png and /dev/null differ
diff --git a/images/image_15.svg b/images/image_15.svg
deleted file mode 100644
index 1f26e4b..0000000
--- a/images/image_15.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_16.svg b/images/image_16.svg
deleted file mode 100644
index cdbba83..0000000
--- a/images/image_16.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_17.svg b/images/image_17.svg
deleted file mode 100644
index 3c35be2..0000000
--- a/images/image_17.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_18.svg b/images/image_18.svg
deleted file mode 100644
index 4ac79b5..0000000
--- a/images/image_18.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_19.svg b/images/image_19.svg
deleted file mode 100644
index 5611eb9..0000000
--- a/images/image_19.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_2.svg b/images/image_2.svg
deleted file mode 100644
index 33f45f5..0000000
--- a/images/image_2.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_20.svg b/images/image_20.svg
deleted file mode 100644
index c51f5c9..0000000
--- a/images/image_20.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_21.svg b/images/image_21.svg
deleted file mode 100644
index defb2cb..0000000
--- a/images/image_21.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_22.png b/images/image_22.png
deleted file mode 100644
index 44e7516..0000000
Binary files a/images/image_22.png and /dev/null differ
diff --git a/images/image_23.png b/images/image_23.png
deleted file mode 100644
index e2065da..0000000
Binary files a/images/image_23.png and /dev/null differ
diff --git a/images/image_24.svg b/images/image_24.svg
deleted file mode 100644
index 613e9cc..0000000
--- a/images/image_24.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_25.png b/images/image_25.png
deleted file mode 100644
index 4cc50d0..0000000
Binary files a/images/image_25.png and /dev/null differ
diff --git a/images/image_26.svg b/images/image_26.svg
deleted file mode 100644
index 38041b7..0000000
--- a/images/image_26.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_27.png b/images/image_27.png
deleted file mode 100644
index 44e7516..0000000
Binary files a/images/image_27.png and /dev/null differ
diff --git a/images/image_28.png b/images/image_28.png
deleted file mode 100644
index 92c7995..0000000
Binary files a/images/image_28.png and /dev/null differ
diff --git a/images/image_29.svg b/images/image_29.svg
deleted file mode 100644
index 52281b0..0000000
--- a/images/image_29.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_3.svg b/images/image_3.svg
deleted file mode 100644
index e02d21c..0000000
--- a/images/image_3.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_30.svg b/images/image_30.svg
deleted file mode 100644
index 28ef773..0000000
--- a/images/image_30.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_31.svg b/images/image_31.svg
deleted file mode 100644
index 90b6eea..0000000
--- a/images/image_31.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_32.svg b/images/image_32.svg
deleted file mode 100644
index 188b0b2..0000000
--- a/images/image_32.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_33.svg b/images/image_33.svg
deleted file mode 100644
index 21f7656..0000000
--- a/images/image_33.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_34.svg b/images/image_34.svg
deleted file mode 100644
index a19b3eb..0000000
--- a/images/image_34.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_35.svg b/images/image_35.svg
deleted file mode 100644
index bbeeb48..0000000
--- a/images/image_35.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_36.svg b/images/image_36.svg
deleted file mode 100644
index aac8682..0000000
--- a/images/image_36.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_37.svg b/images/image_37.svg
deleted file mode 100644
index fb54d1e..0000000
--- a/images/image_37.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_38.svg b/images/image_38.svg
deleted file mode 100644
index cbfa599..0000000
--- a/images/image_38.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_39.svg b/images/image_39.svg
deleted file mode 100644
index 708177f..0000000
--- a/images/image_39.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_4.svg b/images/image_4.svg
deleted file mode 100644
index d6fd4b7..0000000
--- a/images/image_4.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_40.svg b/images/image_40.svg
deleted file mode 100644
index 5c33cdc..0000000
--- a/images/image_40.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_41.svg b/images/image_41.svg
deleted file mode 100644
index 3a2bb18..0000000
--- a/images/image_41.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_42.svg b/images/image_42.svg
deleted file mode 100644
index 8773a4a..0000000
--- a/images/image_42.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_43.svg b/images/image_43.svg
deleted file mode 100644
index 7fa1901..0000000
--- a/images/image_43.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_44.svg b/images/image_44.svg
deleted file mode 100644
index ab2e9a7..0000000
--- a/images/image_44.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_45.svg b/images/image_45.svg
deleted file mode 100644
index c70beb8..0000000
--- a/images/image_45.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_46.svg b/images/image_46.svg
deleted file mode 100644
index 2ac3b8d..0000000
--- a/images/image_46.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_47.svg b/images/image_47.svg
deleted file mode 100644
index 7016ecf..0000000
--- a/images/image_47.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_48.svg b/images/image_48.svg
deleted file mode 100644
index 6886bc7..0000000
--- a/images/image_48.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_49.svg b/images/image_49.svg
deleted file mode 100644
index 2465da7..0000000
--- a/images/image_49.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_5.png b/images/image_5.png
deleted file mode 100644
index 40abed4..0000000
Binary files a/images/image_5.png and /dev/null differ
diff --git a/images/image_50.svg b/images/image_50.svg
deleted file mode 100644
index a016667..0000000
--- a/images/image_50.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_51.svg b/images/image_51.svg
deleted file mode 100644
index 0364e0b..0000000
--- a/images/image_51.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_52.svg b/images/image_52.svg
deleted file mode 100644
index 115c375..0000000
--- a/images/image_52.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_53.png b/images/image_53.png
deleted file mode 100644
index f63df4e..0000000
Binary files a/images/image_53.png and /dev/null differ
diff --git a/images/image_54.svg b/images/image_54.svg
deleted file mode 100644
index 12eadbf..0000000
--- a/images/image_54.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_55.svg b/images/image_55.svg
deleted file mode 100644
index 8c46c0a..0000000
--- a/images/image_55.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_56.svg b/images/image_56.svg
deleted file mode 100644
index 1609744..0000000
--- a/images/image_56.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_57.svg b/images/image_57.svg
deleted file mode 100644
index abf207f..0000000
--- a/images/image_57.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_58.svg b/images/image_58.svg
deleted file mode 100644
index d69d9a8..0000000
--- a/images/image_58.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_59.png b/images/image_59.png
deleted file mode 100644
index 44e7516..0000000
Binary files a/images/image_59.png and /dev/null differ
diff --git a/images/image_6.png b/images/image_6.png
deleted file mode 100644
index 572d861..0000000
Binary files a/images/image_6.png and /dev/null differ
diff --git a/images/image_60.svg b/images/image_60.svg
deleted file mode 100644
index 0c3f339..0000000
--- a/images/image_60.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_61.svg b/images/image_61.svg
deleted file mode 100644
index 9093193..0000000
--- a/images/image_61.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_62.png b/images/image_62.png
deleted file mode 100644
index d8adb7a..0000000
Binary files a/images/image_62.png and /dev/null differ
diff --git a/images/image_63.svg b/images/image_63.svg
deleted file mode 100644
index 7861e45..0000000
--- a/images/image_63.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_64.png b/images/image_64.png
deleted file mode 100644
index dc4106b..0000000
Binary files a/images/image_64.png and /dev/null differ
diff --git a/images/image_65.png b/images/image_65.png
deleted file mode 100644
index de9b499..0000000
Binary files a/images/image_65.png and /dev/null differ
diff --git a/images/image_66.png b/images/image_66.png
deleted file mode 100644
index a4ee7a4..0000000
Binary files a/images/image_66.png and /dev/null differ
diff --git a/images/image_67.png b/images/image_67.png
deleted file mode 100644
index 5c8a2c8..0000000
Binary files a/images/image_67.png and /dev/null differ
diff --git a/images/image_68.png b/images/image_68.png
deleted file mode 100644
index cee79fc..0000000
Binary files a/images/image_68.png and /dev/null differ
diff --git a/images/image_69.png b/images/image_69.png
deleted file mode 100644
index f6fe9b7..0000000
Binary files a/images/image_69.png and /dev/null differ
diff --git a/images/image_7.png b/images/image_7.png
deleted file mode 100644
index 6d965c0..0000000
Binary files a/images/image_7.png and /dev/null differ
diff --git a/images/image_70.svg b/images/image_70.svg
deleted file mode 100644
index d2c4005..0000000
--- a/images/image_70.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_71.svg b/images/image_71.svg
deleted file mode 100644
index 836d620..0000000
--- a/images/image_71.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_72.png b/images/image_72.png
deleted file mode 100644
index 2c82927..0000000
Binary files a/images/image_72.png and /dev/null differ
diff --git a/images/image_73.png b/images/image_73.png
deleted file mode 100644
index 58c8395..0000000
Binary files a/images/image_73.png and /dev/null differ
diff --git a/images/image_74.png b/images/image_74.png
deleted file mode 100644
index 799dd18..0000000
Binary files a/images/image_74.png and /dev/null differ
diff --git a/images/image_75.png b/images/image_75.png
deleted file mode 100644
index 3d1173a..0000000
Binary files a/images/image_75.png and /dev/null differ
diff --git a/images/image_76.svg b/images/image_76.svg
deleted file mode 100644
index b0154a9..0000000
--- a/images/image_76.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_77.svg b/images/image_77.svg
deleted file mode 100644
index 2132119..0000000
--- a/images/image_77.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_78.svg b/images/image_78.svg
deleted file mode 100644
index df1a681..0000000
--- a/images/image_78.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_79.png b/images/image_79.png
deleted file mode 100644
index acdd1d7..0000000
Binary files a/images/image_79.png and /dev/null differ
diff --git a/images/image_8.png b/images/image_8.png
deleted file mode 100644
index 520f0f6..0000000
Binary files a/images/image_8.png and /dev/null differ
diff --git a/images/image_80.svg b/images/image_80.svg
deleted file mode 100644
index e990781..0000000
--- a/images/image_80.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_81.svg b/images/image_81.svg
deleted file mode 100644
index d6fd4b7..0000000
--- a/images/image_81.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_82.svg b/images/image_82.svg
deleted file mode 100644
index ba9a930..0000000
--- a/images/image_82.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_83.svg b/images/image_83.svg
deleted file mode 100644
index 982ce9f..0000000
--- a/images/image_83.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_84.svg b/images/image_84.svg
deleted file mode 100644
index db9a1fe..0000000
--- a/images/image_84.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_85.svg b/images/image_85.svg
deleted file mode 100644
index f62a975..0000000
--- a/images/image_85.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_86.svg b/images/image_86.svg
deleted file mode 100644
index 733ed5c..0000000
--- a/images/image_86.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_87.svg b/images/image_87.svg
deleted file mode 100644
index 653e580..0000000
--- a/images/image_87.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_88.svg b/images/image_88.svg
deleted file mode 100644
index 03fe0f9..0000000
--- a/images/image_88.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_89.svg b/images/image_89.svg
deleted file mode 100644
index b983169..0000000
--- a/images/image_89.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_9.png b/images/image_9.png
deleted file mode 100644
index f1494dd..0000000
Binary files a/images/image_9.png and /dev/null differ
diff --git a/images/image_90.svg b/images/image_90.svg
deleted file mode 100644
index 031784b..0000000
--- a/images/image_90.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/image_91.svg b/images/image_91.svg
deleted file mode 100644
index c27f510..0000000
--- a/images/image_91.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/resources/project/Project.xml b/resources/project/Project.xml
index e93ed0a..e7171c4 100644
--- a/resources/project/Project.xml
+++ b/resources/project/Project.xml
@@ -26,166 +26,148 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
+
+
-
+
-
-
+
+
+
+
+
diff --git a/tests/tTMDDApp.m b/tests/tTMDDApp.m
new file mode 100644
index 0000000..1957107
--- /dev/null
+++ b/tests/tTMDDApp.m
@@ -0,0 +1,121 @@
+classdef tTMDDApp < matlab.uitest.TestCase
+ properties
+ App
+ end
+
+ methods (TestMethodSetup)
+ function launchApp(testCase)
+ testCase.App = TMDDApp;
+ testCase.addTeardown(@delete,testCase.App)
+ end
+ end
+
+ methods (Test)
+
+ function testStartup(testCase)
+
+ % Check plot update
+ testCase.verifyNotEmpty(testCase.App.ROViewObj.lhRO.XData, "x values for RO are empty");
+ testCase.verifyNotEmpty(testCase.App.ROViewObj.lhRO.YData, "y values for RO are empty");
+ testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug are empty");
+ testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug are empty");
+ testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor are empty");
+ testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor are empty");
+ testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex are empty");
+ testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex are empty");
+
+ % Check NCA table
+ testCase.verifyNotEmpty(testCase.App.NCAViewObj.NCAtable.Data,"NCA table is empty");
+
+ end % testStartup
+
+
+ function testChangeDosingAmountAutomaticUpdate(testCase)
+
+ % Deactivate automatic plot update
+ testCase.App.AutomaticupdateCheckBox.Value = false;
+
+ % Simulate for drug=100
+ testCase.App.DosingAmountField.Value = 100;
+ testCase.App.updateApp();
+
+ oldlhRO_XData = testCase.App.ROViewObj.lhRO.XData;
+ oldlhRO_YData = testCase.App.ROViewObj.lhRO.YData;
+ oldlhDrug_XData = testCase.App.ConcViewObj.lhDrug.XData;
+ oldlhDrug_YData = testCase.App.ConcViewObj.lhDrug.YData;
+ oldlhReceptor_XData = testCase.App.ConcViewObj.lhReceptor.XData;
+ oldlhReceptor_YData = testCase.App.ConcViewObj.lhReceptor.YData;
+ oldlhComplex_XData = testCase.App.ConcViewObj.lhComplex.XData;
+ oldlhComplex_YData = testCase.App.ConcViewObj.lhComplex.YData;
+
+ % Activate automatic plot update
+ testCase.App.AutomaticupdateCheckBox.Value = true;
+
+ % Drag slider
+ testCase.drag(testCase.App.DosingAmountSlider,100,200);
+
+ % Check plot update
+ testCase.verifyNotEqual(oldlhRO_XData, testCase.App.ROViewObj.lhRO.XData, "x values for RO not updated");
+ testCase.verifyNotEqual(oldlhRO_YData, testCase.App.ROViewObj.lhRO.YData, "y values for RO not updated");
+ testCase.verifyNotEqual(oldlhDrug_XData, testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug not updated");
+ testCase.verifyNotEqual(oldlhDrug_YData, testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug not updated");
+ testCase.verifyNotEqual(oldlhReceptor_XData, testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor not updated");
+ testCase.verifyNotEqual(oldlhReceptor_YData, testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor not updated");
+ testCase.verifyNotEqual(oldlhComplex_XData, testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex not updated");
+ testCase.verifyNotEqual(oldlhComplex_YData, testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex not updated");
+
+ % Check that lamp is set to false
+ testCase.verifyFalse(testCase.App.LampViewObj.IsOn);
+
+ end % testChangeDosingAmountAutomaticUpdate
+
+ function testChangeDosingAmountManualUpdate(testCase)
+
+ % Deactivate automatic plot update
+ testCase.App.AutomaticupdateCheckBox.Value = false;
+
+ oldlhRO_XData = testCase.App.ROViewObj.lhRO.XData;
+ oldlhRO_YData = testCase.App.ROViewObj.lhRO.YData;
+ oldlhDrug_XData = testCase.App.ConcViewObj.lhDrug.XData;
+ oldlhDrug_YData = testCase.App.ConcViewObj.lhDrug.YData;
+ oldlhReceptor_XData = testCase.App.ConcViewObj.lhReceptor.XData;
+ oldlhReceptor_YData = testCase.App.ConcViewObj.lhReceptor.YData;
+ oldlhComplex_XData = testCase.App.ConcViewObj.lhComplex.XData;
+ oldlhComplex_YData = testCase.App.ConcViewObj.lhComplex.YData;
+
+ % Drag slider
+ testCase.drag(testCase.App.DosingAmountSlider,100,200);
+
+ % Check plot update
+ testCase.verifyEqual(oldlhRO_XData, testCase.App.ROViewObj.lhRO.XData, "x values for RO not updated");
+ testCase.verifyEqual(oldlhRO_YData, testCase.App.ROViewObj.lhRO.YData, "y values for RO not updated");
+ testCase.verifyEqual(oldlhDrug_XData, testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug not updated");
+ testCase.verifyEqual(oldlhDrug_YData, testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug not updated");
+ testCase.verifyEqual(oldlhReceptor_XData, testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor not updated");
+ testCase.verifyEqual(oldlhReceptor_YData, testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor not updated");
+ testCase.verifyEqual(oldlhComplex_XData, testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex not updated");
+ testCase.verifyEqual(oldlhComplex_YData, testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex not updated");
+
+ % Check that lamp is set to false
+ testCase.verifyTrue(testCase.App.LampViewObj.IsOn);
+
+ % Update app to run simulation manually
+ testCase.App.updateApp();
+
+ % Check plot update
+ testCase.verifyNotEqual(oldlhRO_XData, testCase.App.ROViewObj.lhRO.XData, "x values for RO not updated");
+ testCase.verifyNotEqual(oldlhRO_YData, testCase.App.ROViewObj.lhRO.YData, "y values for RO not updated");
+ testCase.verifyNotEqual(oldlhDrug_XData, testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug not updated");
+ testCase.verifyNotEqual(oldlhDrug_YData, testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug not updated");
+ testCase.verifyNotEqual(oldlhReceptor_XData, testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor not updated");
+ testCase.verifyNotEqual(oldlhReceptor_YData, testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor not updated");
+ testCase.verifyNotEqual(oldlhComplex_XData, testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex not updated");
+ testCase.verifyNotEqual(oldlhComplex_YData, testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex not updated");
+
+ % Check that lamp is set to false
+ testCase.verifyFalse(testCase.App.LampViewObj.IsOn);
+
+ end % testChangeDosingAmountManualUpdate
+
+ end
+end
\ No newline at end of file
diff --git a/tests/testIsLeapYear.m b/tests/testIsLeapYear.m
deleted file mode 100644
index c028ad2..0000000
--- a/tests/testIsLeapYear.m
+++ /dev/null
@@ -1,28 +0,0 @@
-classdef testIsLeapYear < matlab.unittest.TestCase
-
- properties (TestParameter)
- yearAndIsLeapYear = { ...
- {2000, true}; ...
- {2024, true}; ...
- {2025, false}; ...
- {1985, false}; ...
- {1999, false} };
- end
-
- methods (Test, ParameterCombination = "sequential")
-
- function test_isLeapYear(testCase, yearAndIsLeapYear)
-
- % Extract input and expected output from parameter for clarity
- year = yearAndIsLeapYear{1};
- expected_isLeap = yearAndIsLeapYear{2};
-
- % Exercise the code
- actual_isLeap = isLeapYear(year);
-
- % Verify results
- testCase.verifyEqual(actual_isLeap, expected_isLeap);
- end
- end
-end
-
diff --git a/tests/testSimpleSort.m b/tests/testSimpleSort.m
deleted file mode 100644
index 47d0ba2..0000000
--- a/tests/testSimpleSort.m
+++ /dev/null
@@ -1,90 +0,0 @@
-classdef testSimpleSort < matlab.unittest.TestCase
-
- properties (TestParameter)
- inputValue = struct( ...
- ScalarPositive = 5, ...
- ScalarNegative = -7, ...
- ScalarZero = 0, ...
- VectorLength2 = [1649,42], ...
- VectorLength10 = [90, 80, 74, 6, 8, 9, 80, 95, 69, 14], ...
- VectorLength20 = [73, 12, 12, 65, 33, 66, 75, 59, 75, 24, ...
- 74, 98, 87, 9, 37, 37, 69, 60, 79, 37], ...
- Empty = []);
- end
-
- methods (Test)
-
- function testSimpleSort_ExampleBasedTest(testCase)
- % This is an example-based test using a hardcoded input and
- % expected output
-
- % Define inputs
- in = [3,5,2,8,1,2,6];
-
- % Define expected outputs
- expectedOut = [1,2,2,3,5,6,8];
-
- % Exercise function
- actualOut = simpleSort(in);
-
- % Verify results
- testCase.verifyEqual(actualOut,expectedOut);
- end
-
-
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % Below is a property-based test that is missing the logic to %
- % test the properties of the result. Uncomment and update the %
- % local functions at the bottom of the class to make it pass. % %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- % function testSimpleSort_PropertyBasedTest(testCase, inputValue)
- % % Create a property-based test for simpleSort
- %
- % % Another way to test a code is by identifying "properties"
- % % (i.e., characteristics) of the results it produces that stay
- % % the same no matter what the input is. Once these properties
- % % are identified, you can write tests that check these
- % % properties against many different test inputs. Being able to
- % % run tests against many different inputs (even randomly
- % % generated inputs) can sometimes help you discover bugs and
- % % edge cases that you might have missed with a smaller sample
- % % of test inputs.
- %
- % % For simpleSort, the properties of the algorithm are:
- % % - Output is sorted in ascending order
- % % - Output has the same number of elements as the input
- %
- %
- % % Exercise function
- % result = simpleSort(inputValue);
- %
- %
- % % Verify that the result is sorted in ascending order
- % % INSTRUCTION: Fill out the "checkIsSortedAscending" local
- % % function at the bottom of this file so that it
- % % returns true when the result is sorted in
- % % ascending order and false when it is not
- % isSortedAscending = checkIsSortedAscending(result);
- % testCase.verifyTrue(isSortedAscending);
- %
- % % Verify the result and inputValue have the same number of
- % % elements
- % % INSTRUCTION: Find an existing verification that compares
- % % result against an expected number of elements
- % % and replace ______ with that verification
- % numElementsInput = numel(inputValue);
- % testCase.verify______(result,numElementsInput);
- % end
-
- end
-end
-
-function isSortedAscending = checkIsSortedAscending(result)
-% HOMEWORK: Add code to check if result is sorted in ascending order
-% Note: isSortedAscending should be a logical true/false
-
-% ADD CODE HERE
-
-
-end
diff --git a/tests/tgenerateSimFun.m b/tests/tgenerateSimFun.m
new file mode 100644
index 0000000..74933e1
--- /dev/null
+++ b/tests/tgenerateSimFun.m
@@ -0,0 +1,48 @@
+classdef tgenerateSimFun < matlab.unittest.TestCase
+
+ properties
+ MATfilename = "test_generateSimFun.mat"
+ MATfilefullpath
+ LoadedData
+ end
+
+ properties (TestParameter)
+ fieldName = {"simFun","doseTable","dependenciesSimFun"};
+ end
+
+ methods(Test)
+
+ function testMATfileCreation(testCase)
+ % Verify that the MAT file is created
+ testCase.verifyTrue(isfile(testCase.MATfilefullpath), 'MAT file was not created.');
+ end
+
+ function testSimFunctionCreation(testCase, fieldName)
+ % Verify that the MAT file contains required fields
+ testCase.verifyTrue(isfield(testCase.LoadedData, fieldName), fieldName + " was not saved in " + testCase.MATfilename);
+ end
+
+ %% Have attendees add this test?
+ function testSimFunctionAcceleration(testCase)
+ % Verify that the SimFunction is accelerated
+ testCase.verifyTrue(testCase.LoadedData.simFun.isAccelerated, "simFun was not accelerated.");
+ end
+
+ end
+
+ methods (TestClassSetup)
+
+ function classSetup(testCase)
+ % Set up shared state for all tests.
+
+ % Test if the simulation function is created successfully
+ testCase.MATfilefullpath = generateSimFun(testCase.MATfilename);
+ testCase.LoadedData = load(testCase.MATfilefullpath);
+
+ % Tear down with testCase.addTeardown.
+ testCase.addTeardown(@delete,testCase.MATfilefullpath);
+
+ end
+
+ end
+end
\ No newline at end of file