diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0118039..256b8e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,16 +8,22 @@ on: branches: [ release ] workflow_dispatch: +# Add permission to write GitHub pages +permissions: + contents: write + pages: write + id-token: write + jobs: test: strategy: fail-fast: false matrix: - MATLABVersion: [R2021a,R2021b,R2022a,R2022b,R2023a,R2023b,R2024a] + MATLABVersion: [R2024a,R2024b] runs-on: ubuntu-latest steps: # Checks-out your repository - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Sets up a display server - name: Start display server @@ -32,14 +38,14 @@ jobs: uses: matlab-actions/setup-matlab@v2 with: release: ${{ matrix.MATLABVersion }} - products: + products: > Symbolic_Math_Toolbox Image_Processing_Toolbox - Computer_Vision_Toolbox - Statistics_and_Machine_Learning_Toolbox - Curve_Fitting_Toolbox + Statistics_and_Machine_Learning_Toolbox + Curve_Fitting_Toolbox Automated_Driving_Toolbox + # Run all the tests - name: Run SmokeTests uses: matlab-actions/run-command@v2 @@ -48,10 +54,12 @@ jobs: # Upload the test results as artifact - name: Upload TestResults - uses: actions/upload-artifact@v3.1.3 + if: ${{ always() }} + uses: actions/upload-artifact@v4 with: - name: TestResults - path: ./SoftwareTests/TestResults_${{ matrix.MATLABVersion }}.txt + name: TestResults_${{ matrix.MATLABVersion }} + path: ./public/* + overwrite: true badge: if: ${{ always() }} @@ -62,26 +70,38 @@ jobs: steps: # Checks-out your repository - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Sets up R2023b - name: Setup MATLAB - uses: matlab-actions/setup-matlab@v1 + uses: matlab-actions/setup-matlab@v2 with: - release: R2023b + release: R2024b # Download the test results from artifact - - name: Download TestResults - uses: actions/download-artifact@v2.1.1 + - name: Download All TestResults + uses: actions/download-artifact@v4 with: - name: TestResults - path: ./SoftwareTests/ - + path: public + pattern: TestResults_* + merge-multiple: true + # Create the test results badge - - name: Run CreateBadge - uses: matlab-actions/run-command@v1 + - name: Run PostSmokeTest + uses: matlab-actions/run-command@v2 + with: + command: openProject(pwd); PostSmokeTest; + + # Deploy reports to GitHub pages + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload pages artifact + uses: actions/upload-pages-artifact@v3 with: - command: openProject(pwd); CreateBadge; + path: public + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 # Commit the JSON for the MATLAB releases badge - name: Commit changed files diff --git a/.gitignore b/.gitignore index 1a2519a..d1596f1 100644 --- a/.gitignore +++ b/.gitignore @@ -52,8 +52,5 @@ Data/allStorms.csv Scripts/myLakeData.mat myLakeData.mat -# Test results -SoftwareTests/TestResults_* - # GitLab page folder public/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8d2d7db..c16835c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,42 +24,30 @@ smoke-test: # Make sure that the runner you plan to use matches the tags - matlab stage: test + parallel: + matrix: + - VERSION: [R2024a,R2024b] script: - - matlab -batch "openProject(pwd);RunAllTests(true)" + - Set-Alias -Name matlab -Value "C:\Program Files\MATLAB\$VERSION\bin\matlab.exe" + - matlab -batch "openProject(pwd);RunAllTests" when: always allow_failure: true artifacts: + name: "$VERSION" paths: - public/* - expire_in: 1 years + when: always + pages: tags: - matlab stage: deploy script: - - echo 'Deploying pages' + - matlab -batch "openProject(pwd);PostSmokeTest;" artifacts: paths: - public - -smoke-test-solution: - tags: - - matlab - stage: release - script: - - matlab -batch "proj = openProject(pwd); - addpath(genpath(proj.RootFolder)); - results = runtests(fullfile('InternalFiles','Tests','CI','SolnSmokeTests.m')); - disp(table(results)); assertSuccess(results);" - rules: -# This test should always run when merging to main -# And be available for manual running on any push - - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH - when: always - - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != $CI_DEFAULT_BRANCH - when: manual - allow_failure: true file-test: tags: @@ -87,6 +75,7 @@ release-testing: - matlab -batch "proj = openProject(pwd); cd ..; addpath(genpath(fullfile('utilities','TestingResources'))); + addpath(genpath(fullfile('utilities','Tools'))); runCMTests" rules: # This test should always run when merging to main diff --git a/FunctionLibrary/.gitkeep b/FunctionLibrary/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/FunctionLibrary/CollectData.m b/FunctionLibrary/CollectData.m index 426c209..6428ac6 100644 --- a/FunctionLibrary/CollectData.m +++ b/FunctionLibrary/CollectData.m @@ -12,4 +12,4 @@ roi = drawpolygon(ax); x = roi.Position(:,1); y = roi.Position(:,2); -end \ No newline at end of file +end diff --git a/FunctionLibrary/cnPDE.m b/FunctionLibrary/cnPDE.m index 3903d34..a378a41 100644 --- a/FunctionLibrary/cnPDE.m +++ b/FunctionLibrary/cnPDE.m @@ -69,11 +69,7 @@ % To visualize the outputs hold on delete(ax.Children(1:end-1)); - try - plot(xVals,[alpha(j*dt);u;beta(j*dt)],LineWidth=1,SeriesIndex="none") - catch % If using R2023a or earlier - plot(xVals,[alpha(j*dt);u;beta(j*dt)],"k",LineWidth=1) - end + plot(xVals,[alpha(j*dt);u;beta(j*dt)],LineWidth=1,SeriesIndex="none") subtitle("$t = $"+dt*j) drawnow pause(0.1) diff --git a/FunctionLibrary/explicitPDE.m b/FunctionLibrary/explicitPDE.m index 98d9722..4303c2b 100644 --- a/FunctionLibrary/explicitPDE.m +++ b/FunctionLibrary/explicitPDE.m @@ -66,11 +66,7 @@ % To visualize the outputs hold on delete(ax.Children(1:end-1)); - try - plot(xVals,[alpha((j+1)*dt);u;beta((j+1)*dt)],LineWidth=4,SeriesIndex="none") - catch % If using R2023a or earlier - plot(xVals,[alpha((j+1)*dt);u;beta((j+1)*dt)],"k",LineWidth=4) - end + plot(xVals,[alpha((j+1)*dt);u;beta((j+1)*dt)],"LineWidth",4,SeriesIndex="none") subtitle("$t = $"+dt*(j+1)) drawnow pause(0.1) diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/cnPDESoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/cnPDESoln.m new file mode 100644 index 0000000..32fdc54 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/cnPDESoln.m @@ -0,0 +1,80 @@ +function u = cnPDESoln(f,alpha,beta,tEnd,dx,gamma,L) +% Solve the 1D heat equation u_t = gamma*u_{xx} on a rod of length L +% using the Crank-Nicolson method +% u(t,0) = alpha(t) +% u(t,L) = beta(t) +% u(0,x) = f(x) +% The desired spatial resolution is dx +% Output is u = u(tEnd,x_m), a vector of values on the mesh points + +% Define dt with reference to both error and stability concerns +% Optimal dt for stability +dtOpt = dx; +% Forcing an integer numbers of dt steps that terminate at tEnd +dt = tEnd/ceil(tEnd/dtOpt); + +% % testing %%%%%%%%%% +% dt = 0.005; + +% Set up the helper values for defining the required matrices +numRows = L/dx-1; +mu = gamma*dt/(dx^2); +baseDiag = ones(1,numRows); + +% Define modA for the explicit updating rule +% modA-I = (A-I)/2, where I is the identity matrix +modA = gallery('tridiag',0.5*mu*baseDiag(1:end-1),(1-mu)*baseDiag,0.5*mu*baseDiag(1:end-1)); + +% Define modB for the implicit updating rule +% modB-I = (B-I)/2, where I is the identity matrix +modB = gallery('tridiag',-0.5*mu*baseDiag(1:end-1),(1+mu)*baseDiag,-0.5*mu*baseDiag(1:end-1)); + +% Initialize bAvg = b^(j)+b^(j+1) as a vector of zeros +bAvg = zeros(numRows,1); + +% Define a spatial mesh vector +xVals = linspace(0,L,round(L/dx)+1); + +% Set up a column vector u0 of the initial values of u when t=0 +u0 = f(xVals)'; + +% Initialize the output to the interior points of u0 +u = u0(2:end-1); + +% To visualize the outputs +p = plot(xVals,u0,"LineWidth",2,"SeriesIndex",1); +ax = p.Parent; + +% Set the y limits to reasonable fixed values +minAlpha = min(alpha(0:dt:tEnd)); +maxAlpha = max(alpha(0:dt:tEnd)); +minBeta = min(beta(0:dt:tEnd)); +maxBeta = max(beta(0:dt:tEnd)); +yLower = min([ax.YLim(1),minAlpha,minBeta]); +yUpper = max([ax.YLim(2),maxAlpha,maxBeta]); +scale = (yUpper-yLower)*0.05; +ax.YLim = [yLower-scale yUpper+scale]; + +title("Solving $\frac{\partial u}{\partial t} = \gamma \frac{\partial^2 u}{\partial x^2}$ with Crank-Nicolson","Interpreter","latex") +subtitle("$t=0$","Interpreter","latex") +xlabel("$x$","Interpreter","latex") +ylabel("$u$","Interpreter","latex") + +% Compute new values for halfB*u^(j+1)-b^(j+1) = halfA*u^(j)+b^(j) +% Loop over timesteps to reach tEnd +for j = 1:(tEnd/dt) + bAvg(1) = mu*(alpha((j-1)*dt)+alpha(j*dt))/2; + bAvg(end) = mu*(beta((j-1)*dt)+beta(j*dt))/2; + u = modB\(modA*u+bAvg); + % To visualize the outputs + hold on + delete(ax.Children(1:end-1)); + plot(xVals,[alpha(j*dt);u;beta(j*dt)],"LineWidth",2,"SeriesIndex",2) + subtitle("$t = $"+dt*j) + drawnow + pause(0.1) + hold off + % End visualization code +end +legend(["u(0,x)","u(t,x)"],"Location","north") +end diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/cnPDEu0Soln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/cnPDEu0Soln.m new file mode 100644 index 0000000..6cfec82 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/cnPDEu0Soln.m @@ -0,0 +1,77 @@ +function u = cnPDE(u0,alpha,beta,tEnd,dx,gamma,L,t0) +% Solve the 1D heat equation u_t = gamma*u_{xx} on a rod of length L +% using the Crank-Nicolson method +% u(t,0) = alpha(t) +% u(t,L) = beta(t) +% u(t0,x) = u0 +% The desired spatial resolution is dx +% Output is u = u(tEnd,x_m), a vector of values on the mesh points + +% Define dt with reference to both error and stability concerns +% Optimal dt for stability +dtOpt = dx; +% Forcing an integer numbers of dt steps that terminate at tEnd +dt = tEnd/ceil((tEnd-t0)/dtOpt); + +% % testing %%%%%%%%%% +% dt = 0.005; + +% Set up the helper values for defining the required matrices +numRows = L/dx-1; +mu = gamma*dt/(dx^2); +baseDiag = ones(1,numRows); + +% Define modA for the explicit updating rule +% modA-I = (A-I)/2, where I is the identity matrix +modA = gallery('tridiag',0.5*mu*baseDiag(1:end-1),(1-mu)*baseDiag,0.5*mu*baseDiag(1:end-1)); + +% Define modB for the implicit updating rule +% modB-I = (B-I)/2, where I is the identity matrix +modB = gallery('tridiag',-0.5*mu*baseDiag(1:end-1),(1+mu)*baseDiag,-0.5*mu*baseDiag(1:end-1)); + +% Initialize bAvg = b^(j)+b^(j+1) as a vector of zeros +bAvg = zeros(numRows,1); + +% Define a spatial mesh vector +xVals = linspace(0,L,round(L/dx)+1); + +% Initialize the output to the interior points of u0 +u = u0(2:end-1); + +% To visualize the outputs +p = plot(xVals,u0,"LineWidth",4); +ax = p.Parent; + +% Set the y limits to reasonable fixed values +minAlpha = min(alpha(0:dt:tEnd)); +maxAlpha = max(alpha(0:dt:tEnd)); +minBeta = min(beta(0:dt:tEnd)); +maxBeta = max(beta(0:dt:tEnd)); +yLower = min([ax.YLim(1),minAlpha,minBeta]); +yUpper = max([ax.YLim(2),maxAlpha,maxBeta]); +scale = (yUpper-yLower)*0.05; +ax.YLim = [yLower-scale yUpper+scale]; + +title("Solving $\frac{\partial u}{\partial t} = \gamma \frac{\partial^2 u}{\partial x^2}$","Interpreter","latex") +subtitle("$t=0$","Interpreter","latex") +xlabel("$x$","Interpreter","latex") +ylabel("$u$","Interpreter","latex") + +% Compute new values for halfB*u^(j+1)-b^(j+1) = halfA*u^(j)+b^(j) +% Loop over timesteps to reach tEnd +for j = 0:(tEnd/dt - 1) + bAvg(1) = mu*(alpha(j*dt)+alpha((j+1)*dt))/2; + bAvg(end) = mu*(beta(j*dt)+beta((j+1)*dt))/2; + u = modB\(modA*u+bAvg); + % To visualize the outputs + hold on + delete(ax.Children(1:end-1)); + plot(xVals,[alpha((j+1)*dt);u;beta((j+1)*dt)],"LineWidth",4,SeriesIndex="none") + subtitle("$t = $"+dt*(j+1)) + drawnow + pause(0.1) + hold off + % End visualization code +end + +end diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/eulerBackwardDifferenceSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/eulerBackwardDifferenceSoln.m new file mode 100644 index 0000000..cfa38b8 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/eulerBackwardDifferenceSoln.m @@ -0,0 +1,32 @@ +function [tApprox,yApprox]=eulerBackwardDifferenceSoln(f,init,n,h) +% The eulerBackwardDifference function takes four arguments +% f is a function handle, e.g. @(t,y) t.^2.*cos(y) +% init = is the initial value vector [t0 y0] +% h is the step size and +% n is the number of steps to estimate +% +% The function returns two length (n+1) vectors of +% estimated x and y values + +% Initialize the output with the initial value +tApprox = nan(n+1,1); +yApprox = nan(n+1,1); +tApprox(1) = init(1); +yApprox(1) = init(2); + +% Evaluate one step forward using the Euler forward difference method +tApprox(2) = tApprox(1)+h; +yApprox(2) = yApprox(1)+f(tApprox(1),yApprox(1))*h; + +g = @(t,y,yn) y-f(t,y)*h-yn; + +for i = 3:(n+1) + ti = tApprox(i-1)+h; + yn = yApprox(i-1); + gi = @(y) g(ti,y,yn); + yi = fzero(gi,yn); + tApprox(i) = ti; + yApprox(i) = yi; +end + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/eulerMethodDESoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/eulerMethodDESoln.m new file mode 100644 index 0000000..07e1d66 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/eulerMethodDESoln.m @@ -0,0 +1,26 @@ +function [tApprox,yApprox]=eulerMethodDESoln(f,init,n,h) +arguments + f function_handle % derivative dy/dt = f(t,y) + init (1,2) double % initial value [t0 y0] + n (1,1) double {mustBePositive,mustBeInteger} % number of steps + h (1,1) double % step size +end +% f is a function handle, e.g. @(t,y) t.^2.*cos(y) + +% The function returns two length (n+1) vectors of +% estimated x and y values + +% Initialize the output with the initial value +tApprox = nan(n+1,1); +yApprox = nan(n+1,1); +tApprox(1) = init(1); +yApprox(1) = init(2); + +for i = 1:n + xi = tApprox(i)+h; + yi = yApprox(i)+f(tApprox(i),yApprox(i))*h; + tApprox(i+1) = xi; + yApprox(i+1) = yi; +end + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/eulerMethodSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/eulerMethodSoln.m new file mode 100644 index 0000000..72c3120 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/eulerMethodSoln.m @@ -0,0 +1,25 @@ +function [xApprox,yApprox]=eulerMethodSoln(f,init,n,h) +arguments + f function_handle % integrand, e.g. @(x) x.^2 + init (1,2) double % initial value + n (1,1) double {mustBePositive,mustBeInteger} % number of steps + h (1,1) double % step size +end + +% The function returns two length (n+1) vectors of +% estimated x and y values + +% Initialize the output with the initial value +xApprox = nan(n+1,1); +yApprox = nan(n+1,1); +xApprox(1) = init(1); +yApprox(1) = init(2); + +for i = 1:n + xi = xApprox(i)+h; + yi = yApprox(i)+f(xApprox(i))*h; + xApprox(i+1) = xi; + yApprox(i+1) = yi; +end + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/explicitPDESoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/explicitPDESoln.m new file mode 100644 index 0000000..76e947e --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/explicitPDESoln.m @@ -0,0 +1,75 @@ +function u = explicitPDESoln(f,alpha,beta,tEnd,dx,gamma,L) +% Solve the 1D heat equation u_t = gamma*u_{xx} on a rod of length L +% u(t,0) = alpha(t) +% u(t,L) = beta(t) +% u(0,x) = f(x) +% The desired spatial resolution is dx +% Output is u = u(tEnd,x_m), a vector of values on the mesh points + +% Define dt with reference to both error and stability concerns +% Optimal dt for stability +dtOpt = dx^2/(2*gamma); +% Forcing an integer numbers of dt steps that terminate at tEnd +dt = tEnd/ceil(tEnd/dtOpt); + +% % testing %%%%%%%%%% +% dt = 0.005; + +% Define helper values +numRows = L/dx-1; +mu = gamma*dt/(dx^2); +baseDiag = ones(1,numRows); + +% Define A for the updating rule +% u^(j+1) = A*u^(j)+b^(j) +A = gallery('tridiag',mu*baseDiag(1:end-1),(1-2*mu)*baseDiag,mu*baseDiag(1:end-1)); + +% Initialize b as a vector of zeros +b = zeros(numRows,1); + +% Define a spatial mesh vector +xVals = linspace(0,L,round(L/dx)+1); + +% Set up a column vector u0 of the initial values of u when t=0 +u0 = (f(xVals))'; + +% Initialize the output to the interior points of u0 +u = u0(2:end-1); + +% To visualize the outputs +p = plot(xVals,u0,"LineWidth",4); +ax = p.Parent; + +% Set the y limits to reasonable fixed values +minAlpha = min(alpha(0:dt:tEnd)); +maxAlpha = max(alpha(0:dt:tEnd)); +minBeta = min(beta(0:dt:tEnd)); +maxBeta = max(beta(0:dt:tEnd)); +yLower = min([ax.YLim(1),minAlpha,minBeta]); +yUpper = max([ax.YLim(2),maxAlpha,maxBeta]); +scale = (yUpper-yLower)*0.05; +ax.YLim = [yLower-scale yUpper+scale]; + +title("Solving $\frac{\partial u}{\partial t} = \gamma \frac{\partial^2 u}{\partial x^2}$ explicitly","Interpreter","latex") +subtitle("$t=0$","Interpreter","latex") +xlabel("$x$","Interpreter","latex") +ylabel("$u$","Interpreter","latex") + +% Compute new values for u^(j+1) = Au^(j)+b^(j) +% Loop over timesteps to reach tEnd +for j = 0:(tEnd/dt - 1) + b(1) = alpha(j*dt); + b(end) = beta(j*dt); + u = A*u+b; + % To visualize the outputs + hold on + delete(ax.Children(1:end-1)); + plot(xVals,[alpha((j+1)*dt);u;beta((j+1)*dt)],"SeriesIndex",2,"LineWidth",4) + subtitle("$t = $"+dt*(j+1)) + drawnow + pause(0.1) + hold off + % End visualization code +end + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/gauss2ptSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/gauss2ptSoln.m new file mode 100644 index 0000000..8b89e73 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/gauss2ptSoln.m @@ -0,0 +1,18 @@ +function Fapprox = gauss2ptSoln(f,a,b) +% gauss2pt takes three arguments +% f is a function handle +% a and b are the bounds of a definite integral +% +% Fapprox returns the Gaussian 2 point approximation of the +% integral from a to b of f(x) dx +w1 = 1; +w2 = 1; +x1 = -1/sqrt(3); +x2 = 1/sqrt(3); + +% Change variables from [-1,1] to [a,b] +scaledWeights = (b-a)/2*[w1 w2]; +scaledX = (b-a)/2*[x1; x2]+(b+a)/2; + +Fapprox = scaledWeights*f(scaledX); +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/implicitPDESoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/implicitPDESoln.m new file mode 100644 index 0000000..5432c56 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/implicitPDESoln.m @@ -0,0 +1,74 @@ +function u = implicitPDESoln(f,alpha,beta,tEnd,dx,gamma,L) +% Solve the 1D heat equation u_t = gamma*u_{xx} on a rod of length L +% u(t,0) = alpha(t) +% u(t,L) = beta(t) +% u(0,x) = f(x) +% The desired spatial resolution is dx +% Output is u = u(tEnd,x_m), a vector of values on the mesh points + + +% Define dt with reference to both error and stability concerns +% Optimal dt for stability +dtOpt = dx^2; +% Forcing an integer numbers of dt steps that terminate at tEnd +dt = tEnd/ceil(tEnd/dtOpt); + +% % testing %%%%%%%%%% +% dt = 0.005; + +% Define B for the updating rule +% Bu^(j+1)-b^(j+1) = u^(j) +numRows = L/dx-1; +mu = gamma*dt/(dx^2); +baseDiag = ones(1,numRows); +B = gallery('tridiag',-mu*baseDiag(1:end-1),(1+2*mu)*baseDiag,-mu*baseDiag(1:end-1)); + +% Initialize b as a vector of zeros +b = zeros(numRows,1); + +% Define a spatial mesh vector +xVals = linspace(0,L,round(L/dx)+1); + +% Set up a column vector u0 of the initial values of u when t=0 +u0 = (f(xVals))'; + +% Initialize the output to the interior points of u0 +u = u0(2:end-1); + +% To visualize the outputs +p = plot(xVals,u0,"LineWidth",4); +ax = p.Parent; + +% Set the y limits to reasonable fixed values +minAlpha = min(alpha(0:dt:tEnd)); +maxAlpha = max(alpha(0:dt:tEnd)); +minBeta = min(beta(0:dt:tEnd)); +maxBeta = max(beta(0:dt:tEnd)); +yLower = min([ax.YLim(1),minAlpha,minBeta]); +yUpper = max([ax.YLim(2),maxAlpha,maxBeta]); +scale = (yUpper-yLower)*0.05; +ax.YLim = [yLower-scale yUpper+scale]; + +title("Solving $\frac{\partial u}{\partial t} = \gamma \frac{\partial^2 u}{\partial x^2}$ implicitly","Interpreter","latex") +subtitle("$t=0$","Interpreter","latex") +xlabel("$x$","Interpreter","latex") +ylabel("$u$","Interpreter","latex") + +% Compute new values for B*u^(j+1) - b^(j+1) = Au^(j) +% Loop over timesteps to reach tEnd +for j = 0:(tEnd/dt - 1) + b(1) = alpha((j+1)*dt); + b(end) = beta((j+1)*dt); + u = B\(u+b); + % To visualize the outputs + hold on + delete(ax.Children(1:end-1)); + plot(xVals,[alpha((j+1)*dt);u;beta((j+1)*dt)],"LineWidth",4,SeriesIndex="none") + subtitle("$t = $"+dt*(j+1)) + drawnow + pause(0.1) + hold off + % End visualization code +end + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/improvedEulerSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/improvedEulerSoln.m new file mode 100644 index 0000000..5fe33e8 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/improvedEulerSoln.m @@ -0,0 +1,30 @@ +function [tApprox,yApprox]=improvedEulerSoln(f,init,n,h) +% The improvedEuler function takes four arguments +% f is a function handle, e.g. @(t,y) t.^2.*cos(y) +% init = is the initial value vector [t0 y0] +% h is the step size and +% n is the number of steps to estimate +% +% The function returns two length (n+1) vectors of +% estimated x and y values + +% This method is also called the Heun formula + +% Initialize the output with the initial value +tApprox = nan(n+1,1); +yApprox = nan(n+1,1); +tApprox(1) = init(1); +yApprox(1) = init(2); + + +for i = 2:(n+1) + tPrev = tApprox(i-1); + ti = tPrev+h; + yPrev = yApprox(i-1); + yiGuess = yPrev+f(tPrev,yPrev)*h; + yiImproved = (yiGuess+yPrev+f(ti,yiGuess)*h)/2; + tApprox(i) = ti; + yApprox(i) = yiImproved; +end + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/linInterpSimpSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/linInterpSimpSoln.m new file mode 100644 index 0000000..ebeac51 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/linInterpSimpSoln.m @@ -0,0 +1,32 @@ +function yNew = linInterpSimp(xData,yData,xNew) +% linInterp interpolates the point(s) (xNew(i),yNew(i)) using a +% piecewise linear interpolation on the input data xData +% and output data yData + +% Initialize output values vector +yNew = nan(size(xNew)); + +% Is xData decreasing? +if xData(2)-xData(1) < 0 + % Reorder xData and yData so that xData is increasing + xData = xData(end:-1:1); + yData = yData(end:-1:1); +end + +% Check each value in xNew and determine its +% corresponding interpolated value in yNew +for k = 1:length(xNew) + curVal = xNew(k); + for j = 1:length(xData)-1 + if curVal == xData(j) + yNew(k) = yData(j); + elseif (xData(j) < curVal) && (curVal < xData(j+1)) + yNew(k) = yData(j) + (curVal - xData(j))*(yData(j+1)-yData(j))/(xData(j+1)-xData(j)); + end + end + if curVal == xData(end) + yNew = yData(end); + end +end + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/linInterpSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/linInterpSoln.m new file mode 100644 index 0000000..3e04533 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/linInterpSoln.m @@ -0,0 +1,76 @@ +function yNew = linInterp(xData,yData,xNew) +% linInterp interpolates the point(s) (xNew(i),yNew(i)) using a +% piecewise linear interpolation on the input data xData +% and output data yData + +% Initialize output values vector +yNew = nan(size(xNew)); + +% Check whether the input values make sense and have the expected shape +if isvector(xData) && isvector(xNew) + % Ensure that xData is a row vector + if ~isrow(xData) + xData = xData'; + end + + % Ensure that xNew is a row vector + if ~isrow(xNew) + xNew = xNew'; + end +else + warning("The input data must be vectors.") + return +end + +if max(xNew)>max(xData) || min(xNew)0) == length(xData)-1 + % xData is increasing + flag = 1; +elseif nnz(diff(xData)<0) == length(xData)-1 + % xData is decreasing + flag = -1; +else + warning("The input data is not properly ordered. " + ... + "The xData must be monotonic.") + return +end + +% Find the closest datapoint in xData for each value xNew +[distVal,idx] = min((xNew'-xData).^2,[],2); +midIdx = distVal~=0; + +% Calculate the values of yNew that occur on values of yData +yNew(~midIdx) = yData(idx(~midIdx)); + +% Identify the indices of the endpoints of the relevant interval for +% non-endpoint values of xNew +altEndPt = sign((xNew(midIdx)-xData(idx(midIdx))).*flag); + +% if max(idx(altEndPt==0))< length(xData) +% altEndPt(altEndPt==0) = 1; +% elseif min(idx(altEndPt==0))< length(xData) +rowIdx = idx'; +endIdx = sort([rowIdx(midIdx);rowIdx(midIdx)+altEndPt]); + +% Compute the x and y values of the endpoints +endxLeft = xData(endIdx(1,:)); +endxRight = xData(endIdx(2,:)); +endyLeft = yData(endIdx(1,:)); +endyRight = yData(endIdx(2,:)); + + +% Use point-slope form to evaluate yNew on intervior points +% y = y_1 + m*(x-x_1) +yNew(midIdx) = endyLeft + (endyRight-endyLeft)./(endxRight-endxLeft)... + .*(xNew(midIdx)-endxLeft); + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/pcHInterpSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/pcHInterpSoln.m new file mode 100644 index 0000000..39ea544 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/pcHInterpSoln.m @@ -0,0 +1,97 @@ +function yNew = pcHInterpSoln(xData,yData,xNew) +% xData is assumed to be a uniformly increasing vector and all values +% xNew should be contained in the interval [xData(1),xData(end)] +% Use the piecewise cubic spline formulas defined in interpolation.m +% to compute interpolated values yNew at points xNew + +% %% Ensure that xData and yData are column vectors +[xRows,~] = size(xData); +[yRows,~] = size(yData); +if xRows == 1 + xData = xData'; +end +if yRows == 1 + yData = yData'; +end + +% %% Set up the value of n = number of intervals between points in xData +n = length(xData); + +% %% Calculate the vector of values h where +% h(i) = h_i = xData(i+1)-xData(i) +h = xData(2:end)-xData(1:end-1); + +% %% Calculate the vector of slopes m where +% m(i) = m_i = (y_(i+1)-y_i)/h(i) +% Remember to use pointwise operations +m = (yData(2:end)-yData(1:end-1))./h; + +% %% Determine the values of the slopes for the interpolant +d = nan(n,1); +% %% Start by calculating the slopes at interior points +% If the sign of the slope changes between xData(i-1) and xData(i+1), or +% if the slope is 0 in interval i-1 or i, set d(i) to be 0. +% Otherwise, use a weighted centered difference approximation +% where (w1+w2)/d(i) = w1/m(i-1)+w2/m(i) +% with w1 = 2*h(i)+h(i-1) and w2 = 2*h(i-1)+h(i) +for i = 2:n-1 + if m(i-1) == 0 || m(i)/m(i-1) <= 0 + % Check for local minima or maxima + d(i) = 0; + else + % Compute weights + w1 = 2*h(i)+h(i-1); + w2 = 2*h(i-1)+h(i); + d(i) = (w1+w2)/(w1/m(i-1)+w2/m(i)); + end +end + +% Add the slopes at i=1 and i=n using the formula +% ((2*h1+h2)*m1-h1*m2)/(h1+h2) where +% h1 is the length of the first step back/forward and +% h2 is the length of the second step back/foward and +% m1 is the slope over the first interval back/forward and +% m2 is the slope over the second interval back/forward +d(1) = ((2*h(1)+h(2))*m(1)-h(1)*m(2))/(h(1)+h(2)); +d(n) = ((2*h(n-1)+h(n-2))*m(n-1)-h(n-1)*m(n-2))/(h(n-1)+h(n-2)); + +d(1) = checkOvershoot(d(1),m(1),m(2)); +d(n) = checkOvershoot(d(n),m(n-1),m(n-2)); + +% %% Set up the coefficients for P(x) in each interval where +% xData(k) <= x < xData(k+1) and P_k(x) = a3*s^3+a2*s^2+a1*s+a0 +a3 = -2*m+d(1:end-1)+d(2:end); +a2 = 3*m-2*d(1:end-1)-d(2:end); +a1 = d(1:end-1); +a0 = yData(1:end-1); + +% %% Initialize the output vector yNew +yNew = nan(size(xNew)); + +% %% Loop over all entries in xNew and compute the interpolated value +for i = 1:length(xNew) + % For each value xNew(i), determine the value k such that + % xData(k) <= xNew(i) < xData(k+1) + j = 1; + while xData(j) <= xNew(i) && j < length(xData) + k=j; + j = j+1; + end + if xNew(i)==xData(end) + yNew(i) = yData(end); + else + % Evaluate the local variables s = xNew(i)-x_k + s = xNew(i)-xData(k); + % Use the polynomial formula P_k(x) to evaluate yNew = P_k(xNew(i)) + yNew(i) = a3(k)*s^3+a2(k)*s^2+a1(k)*s+a0(k); + end +end +end +function d = checkOvershoot(d,m1,m2) +if sign(d) ~= sign(m1) + d=0; +elseif sign(d) ~= sign(m2) & (abs(d)>abs(3*m1)) + d = 3*m1; +end +end + diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/pcSplineSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/pcSplineSoln.m new file mode 100644 index 0000000..5a6e28e --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/pcSplineSoln.m @@ -0,0 +1,93 @@ +function [yNew,d] = pcSplineSoln(xData,yData,xNew) +% xData is assumed to be a uniformly increasing vector and all values +% xNew should be contained in the interval [xData(1),xData(end)] +% Use the piecewise cubic spline formulas defined in interpolation.m +% to compute interpolated values yNew at points xNew + +% %% Ensure that xData and yData are both column vectors +[xRows,~] = size(xData); +[yRows,~] = size(yData); +if xRows == 1 + xData = xData'; +end +if yRows == 1 + yData = yData'; +end + +% %% Set up the value of n = number of points in xData +n = length(xData); + +% %% Calculate the vector of values h where +% h(i) = h_i = xData(i+1)-xData(i) +h = xData(2:end)-xData(1:end-1); + +% %% Calculate the vector of slopes m where +% m(i) = m_i = (y_(i+1)-y_i)/h(i) +% Remember to use pointwise operations +m = (yData(2:end)-yData(1:end-1))./h; + +% %% Set up the vector r +% r(1) = 5/2m_1 + 1/2m_2 and r(n) = 1/2m_(n-2)+5/2m_n-1 +% with the middle values all given by +% r(i) = 3*(h(i)m(i-1)+h(i-1)*m(i)) +% Remember to use pointwise operations +r = nan(n,1); +r(1) = 5/2*m(1)+m(2)/2; +r(n) = m(n-2)/2+5/2*m(n-1); +r(2:n-1) = 3*(h(2:n-1).*m(1:n-2)+h(1:n-2).*m(2:n-1)); + + +% %% Set up the vectors of diagonals for A +mainDiag = ones(1,n); +plus1Diag = mainDiag(1:end-1); +minus1Diag = mainDiag(1:end-1); + +% mainDiag(1) = h_2 and mainDiag(n) = h_(n-2) +% with the middle values all given by +% mainDiag(i) = 2(h_(i-1)+h_i) +mainDiag(1) = h(2); +mainDiag(n) = h(n-2); +mainDiag(2:n-1) = 2*(h(1:n-2)+h(2:n-1)); + +% plus1Diag(1) = h_2+h_1 and plus1Diag(i) = h_(i-1) +plus1Diag(1) = h(2)+h(1); +plus1Diag(2:end) = h(1:n-2); +% minus1Diag(n-1) = h_(n-1)+h_(n-2) and minus1Diag(i) = h_(i+1) +minus1Diag(n-1) = h(n-1)+h(n-2); +minus1Diag(1:end-1) = h(2:n-1); + +% Set up the matrix A as a sparse tridiagonal matrix +A = gallery("tridiag",minus1Diag,mainDiag,plus1Diag); + +% Use matrix operations to solve for the values of d +d = A\r; + +% %% Set up the coefficients for P(x) in each interval where +% xData(k) <= x < xData(k+1) and P_k(x) = a3*s^3+a2*s^2+a1*s+a0 +a3 = -2*m+d(1:end-1)+d(2:end); +a2 = 3*m-2*d(1:end-1)-d(2:end); +a1 = d(1:end-1); +a0 = yData(1:end-1); + +% %% Initialize the output vector yNew +yNew = nan(size(xNew)); + +% %% Loop over all entries in xNew and compute the interpolated value +for i = 1:length(xNew) + % For each value xNew(i), determine the value k such that + % xData(k) <= xNew(i) < xData(k+1) + j = 1; + while xData(j) <= xNew(i) && j < length(xData) + k=j; + j = j+1; + end + if xNew(i)==xData(end) + yNew(i) = yData(end); + else + % Evaluate the local variables s = xNew(i)-x_k + s = xNew(i)-xData(k); + % Use the polynomial formula P_k(x) to evaluate yNew = P_k(xNew(i)) + yNew(i) = a3(k)*s^3+a2(k)*s^2+a1(k)*s+a0(k); + end +end +end \ No newline at end of file diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/rk4Soln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/rk4Soln.m new file mode 100644 index 0000000..62b8729 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/rk4Soln.m @@ -0,0 +1,27 @@ +function [t,y] = rk4Soln(f,tspan,y0,n) +% rk4 implements a four-step Runge-Kutta method on function f +% over t = tspan(1) to t = tspan(2) where y(tspan(1))=y0 +% using n intervals +% +% t is a vector of t values and y is a vector of estimated y(t) values + +t = (linspace(tspan(1),tspan(2),n+1))'; + +y = nan(n+1,1); + +y(1) = y0; + +for i = 1:n + tLeft = t(i); + tRight = t(i+1); + tMid = (tLeft+tRight)/2; + yLeft = y(i); + h = t(i+1)-t(i); + k1 = f(tLeft,yLeft); + k2 = f(tMid,yLeft+0.5*h*k1); + k3 = f(tMid,yLeft+0.5*h*k2); + k4 = f(tRight,yLeft+h*k3); + y(i+1) = yLeft + (h/6)*(k1+2*k2+2*k3+k4); +end + +end diff --git a/InstructorResources/Solutions/FunctionLibrarySolutions/simpsonsRuleSoln.m b/InstructorResources/Solutions/FunctionLibrarySolutions/simpsonsRuleSoln.m new file mode 100644 index 0000000..e384290 --- /dev/null +++ b/InstructorResources/Solutions/FunctionLibrarySolutions/simpsonsRuleSoln.m @@ -0,0 +1,22 @@ +function area = simpsonsRuleSoln(f,a,b,n) +% simpsonsRule takes four arguments +% f is a function handle +% a and b are the endpoints of the integral +% n is the number of intervals to use for the approximation +% +% area is the value computed by using a three-point Simpson's rule +% approximation on each subinterval + +% Discretize the function on the endpoints of the intervals +endPts = linspace(a,b,n+1); +fEndpts = f(endPts); + +% Discretize the function on the midpoints of the intervals +midPts = (endPts(2:end)+endPts(1:end-1))/2; +fMidpts = f(midPts); + +% Combine the terms via the (h/3)*(f(a) + 4*f((b+a)/2) + f(b)) +area = (b-a)/(6*n)*(sum(fEndpts) + sum(fEndpts(2:end-1)) + 4*sum(fMidpts)); + + +end \ No newline at end of file diff --git a/InstructorResources/Solutions/HandSoln.mlx b/InstructorResources/Solutions/HandSoln.mlx new file mode 100644 index 0000000..f2aac7a Binary files /dev/null and b/InstructorResources/Solutions/HandSoln.mlx differ diff --git a/InstructorResources/Solutions/ImplementExplicitSolverSoln.mlx b/InstructorResources/Solutions/ImplementExplicitSolverSoln.mlx new file mode 100644 index 0000000..2b14ed3 Binary files /dev/null and b/InstructorResources/Solutions/ImplementExplicitSolverSoln.mlx differ diff --git a/InstructorResources/Solutions/InterpolationSoln.mlx b/InstructorResources/Solutions/InterpolationSoln.mlx new file mode 100644 index 0000000..e9ce33b Binary files /dev/null and b/InstructorResources/Solutions/InterpolationSoln.mlx differ diff --git a/InstructorResources/Solutions/MeasureLakeAreaSoln.mlx b/InstructorResources/Solutions/MeasureLakeAreaSoln.mlx new file mode 100644 index 0000000..410786a Binary files /dev/null and b/InstructorResources/Solutions/MeasureLakeAreaSoln.mlx differ diff --git a/InstructorResources/Solutions/NumericalDerivativesSoln.mlx b/InstructorResources/Solutions/NumericalDerivativesSoln.mlx new file mode 100644 index 0000000..47c177d Binary files /dev/null and b/InstructorResources/Solutions/NumericalDerivativesSoln.mlx differ diff --git a/InstructorResources/Solutions/NumericalIntegrationSoln.mlx b/InstructorResources/Solutions/NumericalIntegrationSoln.mlx new file mode 100644 index 0000000..f07dda3 Binary files /dev/null and b/InstructorResources/Solutions/NumericalIntegrationSoln.mlx differ diff --git a/InstructorResources/Solutions/NumericalODEsSoln.mlx b/InstructorResources/Solutions/NumericalODEsSoln.mlx new file mode 100644 index 0000000..abbbc49 Binary files /dev/null and b/InstructorResources/Solutions/NumericalODEsSoln.mlx differ diff --git a/Utilities/OldVersions/NumericalPDEsOld.mlx b/InstructorResources/Solutions/NumericalPDEsSoln.mlx similarity index 89% rename from Utilities/OldVersions/NumericalPDEsOld.mlx rename to InstructorResources/Solutions/NumericalPDEsSoln.mlx index 7cfcc1a..3692132 100644 Binary files a/Utilities/OldVersions/NumericalPDEsOld.mlx and b/InstructorResources/Solutions/NumericalPDEsSoln.mlx differ diff --git a/Utilities/OldVersions/PendulumModelsOld.mlx b/InstructorResources/Solutions/PendulumModelsSoln.mlx similarity index 72% rename from Utilities/OldVersions/PendulumModelsOld.mlx rename to InstructorResources/Solutions/PendulumModelsSoln.mlx index fdb4f24..1b62816 100644 Binary files a/Utilities/OldVersions/PendulumModelsOld.mlx and b/InstructorResources/Solutions/PendulumModelsSoln.mlx differ diff --git a/InstructorResources/Solutions/TrackStormsSoln.mlx b/InstructorResources/Solutions/TrackStormsSoln.mlx new file mode 100644 index 0000000..26f1ab2 Binary files /dev/null and b/InstructorResources/Solutions/TrackStormsSoln.mlx differ diff --git a/InstructorResources/Solutions/myLakeData.mat b/InstructorResources/Solutions/myLakeData.mat new file mode 100644 index 0000000..7be5bdb Binary files /dev/null and b/InstructorResources/Solutions/myLakeData.mat differ diff --git a/InstructorResources/Solutions/myModernLakeData.mat b/InstructorResources/Solutions/myModernLakeData.mat new file mode 100644 index 0000000..413d6f7 Binary files /dev/null and b/InstructorResources/Solutions/myModernLakeData.mat differ diff --git a/README.md b/README.md index 408fc34..4823526 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ -# Numerical Methods with Applications - - -[![View on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/111490-numerical-methods-with-applications) or [![Open in MATLAB Online](https://www.mathworks.com/images/responsive/global/open-in-matlab-online.svg)](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=README.mlx) - -![MATLAB Versions Tested](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2FMathWorks-Teaching-Resources%2FNumerical-Methods-with-Applications%2Frelease%2FImages%2FTestedWith.json) -**Curriculum Module** - -_Created with R2021b. Compatible with R2021b and later releases._ +# Numerical Methods with Applications + +[![View on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/111490-numerical-methods-with-applications) or [![Open in MATLAB Online](https://www.mathworks.com/images/responsive/global/open-in-matlab-online.svg)](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=README.mlx) + +![MATLAB Versions Tested](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2FMathWorks-Teaching-Resources%2FNumerical-Methods-with-Applications%2Frelease%2FImages%2FTestedWith.json) + +**Curriculum Module** + +_Created with R2021b. Compatible with R2021b and later releases._ + # Information This curriculum module contains interactive [MATLAB® live scripts](https://www.mathworks.com/products/matlab/live-editor.html) that teach fundamental concepts and basic terminology related to designing and implementing numerical methods related to interpolation, numerical integration and differentiation, and numerical solutions to ordinary and partial differential equations. @@ -32,7 +33,7 @@ This module assumes familiarity with basic programming concepts such as floating ### Accessing the Module ### **On MATLAB Online:** -Use the [OpenInMO.png](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=README.mlx) link to download the module. You will be prompted to log in or create a MathWorks account. The project will be loaded, and you will see an app with several navigation options to get you started. +Use the [OpenInMO.png](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj) link to download the module. You will be prompted to log in or create a MathWorks account. The project will be loaded, and you will see an app with several navigation options to get you started. ### **On Desktop:** @@ -52,30 +53,30 @@ MATLAB® is used throughout. Tools from the Symbolic Math Toolbox™ are used fr # Scripts ## [**Interpolation.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Interpolation.mlx) -| hand.png
| **In this script, students will...**

- define interpolation and explain how it is different from regression and extrapolation
- demonstrate multiple solutions to an interpolation problem, even when interpolating by polynomials
- implement three different interpolation functions
| **Applications**
- Drawing a smooth rendition of their hand
- Tracking the path of a cyclone

**Scaffolded Template Scripts**
[linInterp.m](./FunctionLibrary/linInterp.m)
[pcHInterp.m](./FunctionLibrary/pcHInterp.m)
[pcSpline.m](./FunctionLibrary/pcSpline.m)
| +| hand.png
| **In this script, students will...**

- define interpolation and explain how it is different from regression and extrapolation

- demonstrate multiple solutions to an interpolation problem, even when interpolating by polynomials

- implement three different interpolation functions
| **Applications**

- Drawing a smooth rendition of their hand

- Tracking the path of a cyclone
**Scaffolded Template Scripts**
[linInterp.m](./FunctionLibrary/linInterp.m)
[pcHInterp.m](./FunctionLibrary/pcHInterp.m)
[pcSpline.m](./FunctionLibrary/pcSpline.m)
| | :-- | :-- | :-- | ## Supporting Scripts -- [Hand.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/Hand.mlx) -- [TrackStorms.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/TrackStorms.mlx) -## [**NumericalDerivatives.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/NumericalDerivatives.mlx) -| NoisyDerivative.png
| **In this script, students will...**

- determine numerical derivative approximations formulas
- use Taylor's theorem to calculate the order of the error for a numerical approximation to a derivative
- demonstrate how numerical derivatives can magnify approximation errors
| **Applications**
- Numerical solutions to differential equations
| +- [Hand.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Hand.mlx) +- [TrackStorms.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=TrackStorms.mlx) +## [**NumericalDerivatives.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=NumericalDerivatives.mlx) +| NoisyDerivative.png
| **In this script, students will...**

- determine numerical derivative approximations formulas

- use Taylor's theorem to calculate the order of the error for a numerical approximation to a derivative

- demonstrate how numerical derivatives can magnify approximation errors
| **Applications**

- Numerical solutions to differential equations
| | :-- | :-- | :-- | -## [**NumericalIntegration.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/NumericalIntegration.mlx) -| BakerLakeSR.png
| **In this script, students will...**

- implement Euler's method, Gaussian 2\-point approximations, and Simpson's rule for numerical integration
- explain why higher\-order approximations may not be appropriate in applications
| **Applications**
- Measure the area of a lake

**Scaffolded Template Scripts**
[eulerMethod.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/eulerMethod.m)
[gauss2pt.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/gauss2pt.m)
[simpsonsRule.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/simpsonsRule.m)
| +## [**NumericalIntegration.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=NumericalIntegration.mlx) +| BakerLakeSR.png
| **In this script, students will...**

- implement Euler's method, Gaussian 2\-point approximations, and Simpson's rule for numerical integration

- explain why higher\-order approximations may not be appropriate in applications
| **Applications**

- Measure the area of a lake
**Scaffolded Template Scripts**
[eulerMethod.m](./FunctionLibrary/eulerMethod.m)
[gauss2pt.m](./FunctionLibrary/gauss2pt.m)
[simpsonsRule.m](./FunctionLibrary/simpsonsRule.m)
| | :-- | :-- | :-- | ## Supporting Scripts -- [MeasureLakeArea.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/MeasureLakeArea.mlx) -## [**NumericalODEs.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/NumericalODEs.mlx) -| image_6.png
| **In this script, students will...**

- implement Euler's method for first\-order initial value problems
- calculate the error of their numerical solution
- implement a trapezoidal method
- implement a four\-step Runge\-Kutta method
- compare results with the built\-in MATLAB solver ode45
| **Applications**
- Model a pendulum with increasingly realistic assumptions

**Scaffolded Template Scripts**
[eulerMethodDE.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/eulerMethodDE.m)
[rk4.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/rk4.m)
| +- [MeasureLakeArea.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=MeasureLakeArea.mlx) +## [**NumericalODEs.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=NumericalODEs.mlx) +| image_6.png
| **In this script, students will...**

- implement Euler's method for first\-order initial value problems

- calculate the error of their numerical solution

- implement a trapezoidal method

- implement a four\-step Runge\-Kutta method

- compare results with the built\-in MATLAB solver ode45
| **Applications**

- Model a pendulum with increasingly realistic assumptions
**Scaffolded Template Scripts**
[eulerMethodDE.m](./FunctionLibrary/eulerMethodDE.m)
[rk4.m](./FunctionLibrary/rk4.m)
| | :-- | :-- | :-- | ## Supporting Scripts -- [PendulumModels.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/PendulumModels.mlx) -## [**NumericalPDEs.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=Scripts/NumericalPDEs.mlx) -| heatSoln.gif
| **In this script, students will...**

- identify errors from discretizing the problem and from discretizing the method and choose appropriate parameters to minimize overall error
- explain the importance of stability when choosing a numerical method
- implement explicit, implicit, and Crank\-Nicolson methods to solve a 1\-D heat equation
| **Applications**
- Solve a heat equation

**Scaffolded Template Scripts**
[explicitPDE.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/explicitPDE.m)
[implicitPDE.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/implicitPDE.m)
[cnPDE.m](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=FunctionLibrary/cnPDE.m)
| +- [PendulumModels.mlx](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=PendulumModels.mlx) +## [**NumericalPDEs.mlx**](https://matlab.mathworks.com/open/github/v1?repo=MathWorks-Teaching-Resources/Numerical-Methods-with-Applications&project=NumericalMethods.prj&file=NumericalPDEs.mlx) +| heatSoln.gif
| **In this script, students will...**

- identify errors from discretizing the problem and from discretizing the method and choose appropriate parameters to minimize overall error

- explain the importance of stability when choosing a numerical method

- implement explicit, implicit, and Crank\-Nicolson methods to solve a 1\-D heat equation
| **Applications**

- Solve a heat equation
**Scaffolded Template Scripts**
[explicitPDE.m](./FunctionLibrary/explicitPDE.m)
[implicitPDE.m](./FunctionLibrary/implicitPDE.m)
[cnPDE.m](./FunctionLibrary/cnPDE.m)
| | :-- | :-- | :-- | # License @@ -101,5 +102,4 @@ Looking for more? Find an issue? Have a suggestion? Please contact the [MathWork *©* Copyright 2024 The MathWorks™, Inc - - + diff --git a/Scripts/Hand.mlx b/Scripts/Hand.mlx index 49438b8..80e20e6 100644 Binary files a/Scripts/Hand.mlx and b/Scripts/Hand.mlx differ diff --git a/Scripts/MeasureLakeArea.mlx b/Scripts/MeasureLakeArea.mlx index 09d9ba4..73fcd12 100644 Binary files a/Scripts/MeasureLakeArea.mlx and b/Scripts/MeasureLakeArea.mlx differ diff --git a/Scripts/NumericalODEs.mlx b/Scripts/NumericalODEs.mlx index 1e03476..1bf9dbc 100644 Binary files a/Scripts/NumericalODEs.mlx and b/Scripts/NumericalODEs.mlx differ diff --git a/Scripts/NumericalPDEs.mlx b/Scripts/NumericalPDEs.mlx index 3e6a52e..a20fc3b 100644 Binary files a/Scripts/NumericalPDEs.mlx and b/Scripts/NumericalPDEs.mlx differ diff --git a/SoftwareTests/CheckTestResults.m b/SoftwareTests/CheckTestResults.m index 81c02c5..189346c 100644 --- a/SoftwareTests/CheckTestResults.m +++ b/SoftwareTests/CheckTestResults.m @@ -4,7 +4,7 @@ end properties (ClassSetupParameter) - Project = {''}; + Project = {currentProject()}; end properties (TestParameter) @@ -15,8 +15,8 @@ methods (TestParameterDefinition,Static) function Version = GetResults(Project) - RootFolder = currentProject().RootFolder; - Version = dir(fullfile(RootFolder,"SoftwareTests","TestResults*.txt")); + RootFolder = Project.RootFolder; + Version = dir(fullfile(RootFolder,"public","TestResults*.txt")); Version = extractBetween([Version.name],"TestResults_",".txt"); end @@ -37,9 +37,11 @@ function SetUpSmokeTest(testCase,Project) methods(Test) function CheckResults(testCase,Version) - File = fullfile("SoftwareTests","TestResults_"+Version+".txt"); + File = fullfile("public","TestResults_"+Version+".txt"); Results = readtable(File,TextType="string"); - testCase.verifyTrue(all(Results.Passed)); + if ~all(Results.Passed) + error("Some of the tests did not pass.") + end end end diff --git a/SoftwareTests/CreateBadge.m b/SoftwareTests/CreateBadge.m deleted file mode 100644 index b3c8558..0000000 --- a/SoftwareTests/CreateBadge.m +++ /dev/null @@ -1,28 +0,0 @@ -% Create the test suite with SmokeTest and Function test if they exist -Suite = testsuite("CheckTestResults"); - -% Create a runner with no plugins -Runner = matlab.unittest.TestRunner.withNoPlugins; - -% Run the test suite -Results = Runner.run(Suite); - -% Format the results in a table and save them -Results = table(Results'); -Results = Results(Results.Passed,:); -Version = extractBetween(string(Results.Name),"Version=",")"); - - -% Format the JSON file -Badge = struct; -Badge.schemaVersion = 1; -Badge.label = "Tested with"; -if size(Results,1) >= 1 - Badge.color = "success" - Badge.message = join(Version," | "); -else - Badge.color = "failure"; - Badge.message = "Pipeline fails"; -end -Badge = jsonencode(Badge); -writelines(Badge,fullfile("Images","TestedWith.json")); \ No newline at end of file diff --git a/SoftwareTests/FunctionTests.m b/SoftwareTests/FunctionTests.m index 7246b9d..2d3b15c 100644 --- a/SoftwareTests/FunctionTests.m +++ b/SoftwareTests/FunctionTests.m @@ -1,7 +1,7 @@ classdef FunctionTests < matlab.unittest.TestCase properties (ClassSetupParameter) - Project = {''}; + Project = {currentProject()}; end methods (TestClassSetup) diff --git a/SoftwareTests/PostFiles/PostHand.m b/SoftwareTests/PostFiles/PostHand.m new file mode 100644 index 0000000..232ae97 --- /dev/null +++ b/SoftwareTests/PostFiles/PostHand.m @@ -0,0 +1,8 @@ +% Post-run script for Hand.mlx +% ---- Post-run commands ----- + +clear x y +if exist(fullfile(currentProject().RootFolder,"Data","hand.mat"),"file") + fp = fullfile(currentProject().RootFolder,"Data","hand.mat"); + delete(fp) +end \ No newline at end of file diff --git a/SoftwareTests/PostFiles/PostHandSoln.m b/SoftwareTests/PostFiles/PostHandSoln.m new file mode 100644 index 0000000..7972e87 --- /dev/null +++ b/SoftwareTests/PostFiles/PostHandSoln.m @@ -0,0 +1,8 @@ +% Post-run script for HandSoln.mlx +% ---- Post-run commands ----- + +clear x y +if exist(fullfile(currentProject().RootFolder,"Data","testDrawing.mat"),"file") + fp = fullfile(currentProject().RootFolder,"Data","testDrawing.mat"); + delete(fp) +end diff --git a/SoftwareTests/PostFiles/PostImplementExplicitSolver.m b/SoftwareTests/PostFiles/PostImplementExplicitSolver.m new file mode 100644 index 0000000..7597e66 --- /dev/null +++ b/SoftwareTests/PostFiles/PostImplementExplicitSolver.m @@ -0,0 +1,3 @@ +% Post-run script for ImplementExplicitSolver.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostImplementExplicitSolverSoln.m b/SoftwareTests/PostFiles/PostImplementExplicitSolverSoln.m new file mode 100644 index 0000000..5a23bcc --- /dev/null +++ b/SoftwareTests/PostFiles/PostImplementExplicitSolverSoln.m @@ -0,0 +1,2 @@ +% Post-run script for ImplementExplicitSolverSoln.mlx +% ---- Post-run commands ----- diff --git a/SoftwareTests/PostFiles/PostInterpolation.m b/SoftwareTests/PostFiles/PostInterpolation.m new file mode 100644 index 0000000..b2bd8da --- /dev/null +++ b/SoftwareTests/PostFiles/PostInterpolation.m @@ -0,0 +1,3 @@ +% Post-run script for Interpolation.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostInterpolationSoln.m b/SoftwareTests/PostFiles/PostInterpolationSoln.m new file mode 100644 index 0000000..25034ae --- /dev/null +++ b/SoftwareTests/PostFiles/PostInterpolationSoln.m @@ -0,0 +1,3 @@ +% Post-run script for InterpolationSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostMeasureLakeArea.m b/SoftwareTests/PostFiles/PostMeasureLakeArea.m new file mode 100644 index 0000000..a891103 --- /dev/null +++ b/SoftwareTests/PostFiles/PostMeasureLakeArea.m @@ -0,0 +1,3 @@ +% Post-run script for MeasureLakeArea.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostMeasureLakeAreaSoln.m b/SoftwareTests/PostFiles/PostMeasureLakeAreaSoln.m new file mode 100644 index 0000000..293a364 --- /dev/null +++ b/SoftwareTests/PostFiles/PostMeasureLakeAreaSoln.m @@ -0,0 +1,3 @@ +% Post-run script for MeasureLakeAreaSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalDerivatives.m b/SoftwareTests/PostFiles/PostNumericalDerivatives.m new file mode 100644 index 0000000..fd4db35 --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalDerivatives.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalDerivatives.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalDerivativesSoln.m b/SoftwareTests/PostFiles/PostNumericalDerivativesSoln.m new file mode 100644 index 0000000..bea2935 --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalDerivativesSoln.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalDerivativesSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalIntegration.m b/SoftwareTests/PostFiles/PostNumericalIntegration.m new file mode 100644 index 0000000..8c2905e --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalIntegration.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalIntegration.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalIntegrationSoln.m b/SoftwareTests/PostFiles/PostNumericalIntegrationSoln.m new file mode 100644 index 0000000..0fbcd20 --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalIntegrationSoln.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalIntegrationSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalODEs.m b/SoftwareTests/PostFiles/PostNumericalODEs.m new file mode 100644 index 0000000..9415815 --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalODEs.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalODEs.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalODEsSoln.m b/SoftwareTests/PostFiles/PostNumericalODEsSoln.m new file mode 100644 index 0000000..c6cb8a3 --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalODEsSoln.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalODEsSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalPDEs.m b/SoftwareTests/PostFiles/PostNumericalPDEs.m new file mode 100644 index 0000000..8fd5b1b --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalPDEs.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalPDEs.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostNumericalPDEsSoln.m b/SoftwareTests/PostFiles/PostNumericalPDEsSoln.m new file mode 100644 index 0000000..546a1e7 --- /dev/null +++ b/SoftwareTests/PostFiles/PostNumericalPDEsSoln.m @@ -0,0 +1,3 @@ +% Post-run script for NumericalPDEsSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostPendulumModels.m b/SoftwareTests/PostFiles/PostPendulumModels.m new file mode 100644 index 0000000..693533c --- /dev/null +++ b/SoftwareTests/PostFiles/PostPendulumModels.m @@ -0,0 +1,3 @@ +% Post-run script for PendulumModels.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostPendulumModelsSoln.m b/SoftwareTests/PostFiles/PostPendulumModelsSoln.m new file mode 100644 index 0000000..8581695 --- /dev/null +++ b/SoftwareTests/PostFiles/PostPendulumModelsSoln.m @@ -0,0 +1,3 @@ +% Post-run script for PendulumModelsSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostTrackStorms.m b/SoftwareTests/PostFiles/PostTrackStorms.m new file mode 100644 index 0000000..d495fd5 --- /dev/null +++ b/SoftwareTests/PostFiles/PostTrackStorms.m @@ -0,0 +1,3 @@ +% Post-run script for TrackStorms.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostFiles/PostTrackStormsSoln.m b/SoftwareTests/PostFiles/PostTrackStormsSoln.m new file mode 100644 index 0000000..63ff073 --- /dev/null +++ b/SoftwareTests/PostFiles/PostTrackStormsSoln.m @@ -0,0 +1,3 @@ +% Post-run script for TrackStormsSoln.mlx +% ---- Post-run commands ----- + diff --git a/SoftwareTests/PostSmokeTest.m b/SoftwareTests/PostSmokeTest.m new file mode 100644 index 0000000..7dc6b53 --- /dev/null +++ b/SoftwareTests/PostSmokeTest.m @@ -0,0 +1,66 @@ +function PostSmokeTest(ShowReport) +arguments + ShowReport (1,1) logical = false; +end + +import matlab.unittest.plugins.TestRunnerPlugin; + +% Create the runner: +Runner = matlab.unittest.TestRunner.withTextOutput; + +% Create report folder: +Folder = fullfile(currentProject().RootFolder,"public"); +if ~isfolder(Folder) + mkdir(Folder) +end + +% Add HTML plugin: +Plugin = matlab.unittest.plugins.TestReportPlugin.producingHTML(Folder,... + "IncludingPassingDiagnostics",true,... + "IncludingCommandWindowText",false,... + "LoggingLevel",matlab.automation.Verbosity(1)); +Runner.addPlugin(Plugin); + + +% Create Test Suite +Suite = testsuite("CheckTestResults"); + +% Run the test suite +Results = Runner.run(Suite); + + +% Format the results in a table and save them +Results = table(Results'); +Version = extractBetween(string(Results.Name),"Version=",")"); +Passed = Results.Passed; + +% Add link to other report +File = fileread(fullfile("public","index.html")); +for iVer = 1:length(Version) + File = replace(File,"Version="+Version(iVer),... + sprintf('%s',Version(iVer),"Version="+Version(iVer))); +end +writelines(File,fullfile("public","index.html"),"WriteMode","overwrite"); + +% Format the JSON file +Badge = struct; +Badge.schemaVersion = 1; +Badge.label = "Test Status"; +if all(Passed) + Badge.color = "success"; + Badge.message = join("R"+Version," | "); +elseif any(Passed) + Badge.color = "yellowgreen"; + Badge.message = join("R") +elseif all(~Passed) + Badge.color = "critical"; + Badge.message = join("R"+Version," | "); +end +Badge = jsonencode(Badge); +writelines(Badge,fullfile("Images","TestedWith.json")); + +if ShowReport + web(fullfile(Folder,"index.html")) +end + +end \ No newline at end of file diff --git a/SoftwareTests/PreFiles/PreHand.m b/SoftwareTests/PreFiles/PreHand.m new file mode 100644 index 0000000..75312b8 --- /dev/null +++ b/SoftwareTests/PreFiles/PreHand.m @@ -0,0 +1,11 @@ +% Pre-run script for Hand.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + +CollectData = @()NewCollectData(); + +function varargout = NewCollectData() + load("drawing.mat","x","y") + varargout = {x,y} +end \ No newline at end of file diff --git a/SoftwareTests/PreFiles/PreHandSoln.m b/SoftwareTests/PreFiles/PreHandSoln.m new file mode 100644 index 0000000..be39262 --- /dev/null +++ b/SoftwareTests/PreFiles/PreHandSoln.m @@ -0,0 +1,5 @@ +% Pre-run script for HandSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreImplementExplicitSolver.m b/SoftwareTests/PreFiles/PreImplementExplicitSolver.m new file mode 100644 index 0000000..351a589 --- /dev/null +++ b/SoftwareTests/PreFiles/PreImplementExplicitSolver.m @@ -0,0 +1,5 @@ +% Pre-run script for ImplementExplicitSolver.mlx +% ---- Known Issues ----- +KnownIssuesID = "MATLAB:badsubscript"; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreImplementExplicitSolverSoln.m b/SoftwareTests/PreFiles/PreImplementExplicitSolverSoln.m new file mode 100644 index 0000000..eb3a4ce --- /dev/null +++ b/SoftwareTests/PreFiles/PreImplementExplicitSolverSoln.m @@ -0,0 +1,5 @@ +% Pre-run script for ImplementExplicitSolverSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- +addpath(fullfile(currentProject().RootFolder,"InstructorResources","Solutions","FunctionLibrarySolutions")) diff --git a/SoftwareTests/PreFiles/PreInterpolation.m b/SoftwareTests/PreFiles/PreInterpolation.m new file mode 100644 index 0000000..9b85e5d --- /dev/null +++ b/SoftwareTests/PreFiles/PreInterpolation.m @@ -0,0 +1,5 @@ +% Pre-run script for Interpolation.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreInterpolationSoln.m b/SoftwareTests/PreFiles/PreInterpolationSoln.m new file mode 100644 index 0000000..e2e2e8d --- /dev/null +++ b/SoftwareTests/PreFiles/PreInterpolationSoln.m @@ -0,0 +1,6 @@ +% Pre-run script for InterpolationSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- +addpath(fullfile(currentProject().RootFolder,"InstructorResources","Solutions","FunctionLibrarySolutions")) + \ No newline at end of file diff --git a/SoftwareTests/PreFiles/PreMeasureLakeArea.m b/SoftwareTests/PreFiles/PreMeasureLakeArea.m new file mode 100644 index 0000000..a35fd10 --- /dev/null +++ b/SoftwareTests/PreFiles/PreMeasureLakeArea.m @@ -0,0 +1,12 @@ +% Pre-run script for MeasureLakeArea.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + +load lakeData.mat lakeX lakeY +[~,idx] = max(diff(lakeX)); +x = lakeX([idx:end 1:idx-1]); +y = lakeY([idx:end 1:idx-1]); +p.Position = [x y]; +drawpolygon = p; +openfig = @(in)figure; \ No newline at end of file diff --git a/SoftwareTests/PreFiles/PreMeasureLakeAreaSoln.m b/SoftwareTests/PreFiles/PreMeasureLakeAreaSoln.m new file mode 100644 index 0000000..0cc189d --- /dev/null +++ b/SoftwareTests/PreFiles/PreMeasureLakeAreaSoln.m @@ -0,0 +1,24 @@ +% Pre-run script for MeasureLakeAreaSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- +load myLakeData.mat lakeX lakeY +[~,idx] = max(diff(lakeX)); +x = lakeX([idx:end 1:idx-1]); +y = lakeY([idx:end 1:idx-1]); +p.Position = [x y]; +drawpolygon = p; +openfig = @(in)figure; + +IdentifyLakeShape = @()LoadModernData(); +MeasureGeoScale = @()LoadGeoScale(); + +function roi = LoadModernData +load myModernLakeData.mat modLakeLat modLakeLong +out.Position = [modLakeLat modLakeLong]; +roi=out; +end + +function longScale = LoadGeoScale() +load myModernLakeData.mat longScale +end \ No newline at end of file diff --git a/SoftwareTests/PreFiles/PreNumericalDerivatives.m b/SoftwareTests/PreFiles/PreNumericalDerivatives.m new file mode 100644 index 0000000..aff8e94 --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalDerivatives.m @@ -0,0 +1,5 @@ +% Pre-run script for NumericalDerivatives.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreNumericalDerivativesSoln.m b/SoftwareTests/PreFiles/PreNumericalDerivativesSoln.m new file mode 100644 index 0000000..d02f8c0 --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalDerivativesSoln.m @@ -0,0 +1,5 @@ +% Pre-run script for NumericalDerivativesSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreNumericalIntegration.m b/SoftwareTests/PreFiles/PreNumericalIntegration.m new file mode 100644 index 0000000..58ac7c7 --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalIntegration.m @@ -0,0 +1,5 @@ +% Pre-run script for NumericalIntegration.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreNumericalIntegrationSoln.m b/SoftwareTests/PreFiles/PreNumericalIntegrationSoln.m new file mode 100644 index 0000000..fa818a8 --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalIntegrationSoln.m @@ -0,0 +1,6 @@ +% Pre-run script for NumericalIntegrationSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- +addpath(fullfile(currentProject().RootFolder,"InstructorResources","Solutions","FunctionLibrarySolutions")) + diff --git a/SoftwareTests/PreFiles/PreNumericalODEs.m b/SoftwareTests/PreFiles/PreNumericalODEs.m new file mode 100644 index 0000000..a755614 --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalODEs.m @@ -0,0 +1,5 @@ +% Pre-run script for NumericalODEs.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreNumericalODEsSoln.m b/SoftwareTests/PreFiles/PreNumericalODEsSoln.m new file mode 100644 index 0000000..8b10803 --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalODEsSoln.m @@ -0,0 +1,6 @@ +% Pre-run script for NumericalODEsSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + +addpath(fullfile(currentProject().RootFolder,"InstructorResources","Solutions","FunctionLibrarySolutions")) diff --git a/SoftwareTests/PreFiles/PreNumericalPDEs.m b/SoftwareTests/PreFiles/PreNumericalPDEs.m new file mode 100644 index 0000000..a1cfb6c --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalPDEs.m @@ -0,0 +1,5 @@ +% Pre-run script for NumericalPDEs.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreNumericalPDEsSoln.m b/SoftwareTests/PreFiles/PreNumericalPDEsSoln.m new file mode 100644 index 0000000..e3e5fa8 --- /dev/null +++ b/SoftwareTests/PreFiles/PreNumericalPDEsSoln.m @@ -0,0 +1,6 @@ +% Pre-run script for NumericalPDEsSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + +addpath(fullfile(currentProject().RootFolder,"InstructorResources","Solutions","FunctionLibrarySolutions")) diff --git a/SoftwareTests/PreFiles/PrePendulumModels.m b/SoftwareTests/PreFiles/PrePendulumModels.m new file mode 100644 index 0000000..79e9275 --- /dev/null +++ b/SoftwareTests/PreFiles/PrePendulumModels.m @@ -0,0 +1,5 @@ +% Pre-run script for PendulumModels.mlx +% ---- Known Issues ----- +KnownIssuesID = "MATLAB:unassignedOutputs"; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PrePendulumModelsSoln.m b/SoftwareTests/PreFiles/PrePendulumModelsSoln.m new file mode 100644 index 0000000..64fb219 --- /dev/null +++ b/SoftwareTests/PreFiles/PrePendulumModelsSoln.m @@ -0,0 +1,5 @@ +% Pre-run script for PendulumModelsSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreTrackStorms.m b/SoftwareTests/PreFiles/PreTrackStorms.m new file mode 100644 index 0000000..df88a21 --- /dev/null +++ b/SoftwareTests/PreFiles/PreTrackStorms.m @@ -0,0 +1,5 @@ +% Pre-run script for TrackStorms.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/PreFiles/PreTrackStormsSoln.m b/SoftwareTests/PreFiles/PreTrackStormsSoln.m new file mode 100644 index 0000000..a74d96d --- /dev/null +++ b/SoftwareTests/PreFiles/PreTrackStormsSoln.m @@ -0,0 +1,5 @@ +% Pre-run script for TrackStormsSoln.mlx +% ---- Known Issues ----- +KnownIssuesID = ""; +% ---- Pre-run commands ----- + diff --git a/SoftwareTests/RunAllTests.m b/SoftwareTests/RunAllTests.m index e1e556e..7deba68 100644 --- a/SoftwareTests/RunAllTests.m +++ b/SoftwareTests/RunAllTests.m @@ -1,42 +1,42 @@ -function RunAllTest(EnableReport,ReportFolder) +function RunAllTests(ShowReport) arguments - EnableReport (1,1) logical = false; - ReportFolder (1,1) string = "public"; + ShowReport (1,1) logical = false; end import matlab.unittest.plugins.TestReportPlugin; % Create a runner Runner = matlab.unittest.TestRunner.withTextOutput; -if EnableReport - Folder = fullfile(currentProject().RootFolder,ReportFolder); - if ~isfolder(Folder) - mkdir(Folder) - else - rmdir(Folder,'s') - mkdir(Folder) - end - Plugin = TestReportPlugin.producingHTML(Folder,... - "IncludingPassingDiagnostics",true,... - "IncludingCommandWindowText",true,... - "LoggingLevel",matlab.automation.Verbosity(1)); - Runner.addPlugin(Plugin); +Folder = fullfile(currentProject().RootFolder,"public",version("-release")); +if ~isfolder(Folder) + mkdir(Folder) +else + rmdir(Folder,'s') + mkdir(Folder) end +Plugin = TestReportPlugin.producingHTML(Folder,... + "IncludingPassingDiagnostics",true,... + "IncludingCommandWindowText",true,... + "LoggingLevel",matlab.automation.Verbosity(1)); +Runner.addPlugin(Plugin); + % Create the test suite with SmokeTest and Function test if they exist Suite = testsuite("SmokeTests"); Suite = [Suite testsuite("FunctionTests")]; +Suite = [Suite testsuite("SolnSmokeTests")]; % Run the test suite Results = Runner.run(Suite); -if EnableReport +if ShowReport web(fullfile(Folder,"index.html")) end % Format the results in a table and save them ResultsTable = table(Results') -writetable(ResultsTable,fullfile("SoftwareTests","TestResults_R"+version("-release")+".txt")); +writetable(ResultsTable,fullfile(currentProject().RootFolder,... + "public","TestResults_"+version("-release")+".txt")); % Assert success of test assertSuccess(Results); diff --git a/SoftwareTests/SmokeTests.m b/SoftwareTests/SmokeTests.m index 4de1404..ced801e 100644 --- a/SoftwareTests/SmokeTests.m +++ b/SoftwareTests/SmokeTests.m @@ -1,185 +1,151 @@ -classdef SmokeTests < matlab.unittest.TestCase - - properties (ClassSetupParameter) - Project = {''}; - end - - properties (TestParameter) - Scripts; - end - - methods (TestParameterDefinition,Static) - - function Scripts = GetScriptName(Project) - RootFolder = currentProject().RootFolder; - Scripts = dir(fullfile(RootFolder,"Scripts","*.mlx")); - Scripts = {Scripts.name}; - end - - end - - methods (TestClassSetup) - - function SetUpSmokeTest(testCase,Project) - try - currentProject; - catch ME - warning("Project is not loaded.") - end - end - - - end - - - - methods(Test) - - function SmokeRun(testCase,Scripts) - Filename = string(Scripts); - switch (Filename) - case "Hand.mlx" - disp("Check Hand.mlx by hand because of data collection.") - testCase.verifyTrue(true) - case "ImplementExplicitSolver.mlx" - % ErrorSmokeTest(testCase,Filename) - case "PendulumModels.mlx" - % ErrorSmokeTest(testCase,Filename) - case "MeasureLakeArea.mlx" - SmokeTestWithData(testCase,Filename) - otherwise - % SimpleSmokeTest(testCase,Filename) - end - end - - end - - - methods (Access = private) - - function SmokeTestWithData(testCase,Filename) - % Run the Smoke test - RootFolder = currentProject().RootFolder; - cd(RootFolder) - load lakeData.mat lakeX lakeY - [~,idx] = max(diff(lakeX)); - x = lakeX([idx:end 1:idx-1]); - y = lakeY([idx:end 1:idx-1]); - p.Position = [x y]; - drawpolygon = p; %#ok - openfig = @(in)figure; - disp(">> Running " + Filename); - disp("Note: run this file by hand to check on data collection and openfig()") - try - disp("In 'try'...") - run(fullfile("Scripts",Filename)); - disp("Finished 'try'...") - catch ME - disp("In 'catch' now...") - testCase.verifyTrue(false,ME.message); - end - % Log the opened figures to the test reports - Figures = findall(groot,'Type','figure'); - Figures = flipud(Figures); - if ~isempty(Figures) - for f = 1:size(Figures,1) - FigDiag = matlab.unittest.diagnostics.FigureDiagnostic(Figures(f)); - log(testCase,1,FigDiag); - end - end - close all - - end - - - function ErrorSmokeTest(testCase,Filename) - - % Run the Smoke test - RootFolder = currentProject().RootFolder; - cd(RootFolder) - disp(">> Running " + Filename); - try - flag = 0; - run(fullfile("Scripts",Filename)); - catch ME - MEFlag = 1; - switch Filename - case "PendulumModels.mlx" - if string(ME.identifier) == "MATLAB:unassignedOutputs" - flag = flag+1; - switch flag - case 1 - [t2,theta2] = ode45(@(t,theta) model2t(t,theta,L,g),[t0 tEnd],[theta0 omega0]); - case 2 - [t3,theta3] = ode45(@(t,theta) model3t(t,theta,L,g,M,b,c),[t0 tEnd],[theta0 omega0]); - case 3 - [t4,theta4] = ode45(@(t,theta) model4t(t,theta,L,g,M,m,b,c),[t0 tEnd],[theta0 omega0]); - end - else - MEFlag = 0; - end - case "ImplementExplicitSolver.mlx" - if string(ME.message) == "Index in position 1 exceeds array bounds." - disp("Expected error") - else - MEFlag = 0; - end - otherwise - testCase.verifyTrue(false,"Unexpected file in ErrorSmokeTest") - end - - if MEFlag == 0 - testCase.verifyTrue(false,ME.message); - end - end - - % Log the opened figures to the test reports - Figures = findall(groot,'Type','figure'); - Figures = flipud(Figures); - if ~isempty(Figures) - for f = 1:size(Figures,1) - FigDiag = matlab.unittest.diagnostics.FigureDiagnostic(Figures(f)); - log(testCase,1,FigDiag); - end - end - close all - - end - - - function SimpleSmokeTest(testCase,Filename) - - % Run the Smoke test - RootFolder = currentProject().RootFolder; - cd(RootFolder) - disp(">> Running " + Filename); - try - run(fullfile("Scripts",Filename)); - catch ME - testCase.verifyTrue(false,ME.message); - end - - % Log the opened figures to the test reports - Figures = findall(groot,'Type','figure'); - Figures = flipud(Figures); - if ~isempty(Figures) - for f = 1:size(Figures,1) - FigDiag = matlab.unittest.diagnostics.FigureDiagnostic(Figures(f)); - log(testCase,1,FigDiag); - end - end - close all - - end - - end - - methods (TestClassTeardown) - - function closeAllFigure(testCase) - close all force % Close figure windows - end - - end % methods (TestClassTeardown) - -end \ No newline at end of file +classdef SmokeTests < matlab.unittest.TestCase + + properties + RootFolder + sparedEditors % Files already open when the test starts + end % properties + + properties (ClassSetupParameter) + Project = {currentProject()}; + end % ClassSetupParameter + + properties (TestParameter) + File; + end % TestParameter + + methods (TestParameterDefinition,Static) + + function File = RetrieveFile(Project) %#ok + % Retrieve student template files: + RootFolder = currentProject().RootFolder; + File = dir(fullfile(RootFolder,"Scripts","*.mlx")); + File = {File.name}; + end + + end % Static TestParameterDefinition + + methods (TestClassSetup) + + function SetUpSmokeTest(testCase,Project) %#ok + % Navigate to project root folder: + testCase.RootFolder = Project.RootFolder; + cd(testCase.RootFolder) + + % Close the StartUp app if still open: + delete(findall(groot,'Name','StartUp App')) + + % Log MATLAB version: + testCase.log("Running in " + version) + end + + end % TestClassSetup + + methods(TestMethodSetup) + function recordEditorsToSpare(testCase) + testCase.sparedEditors = matlab.desktop.editor.getAll; + testCase.sparedEditors = {testCase.sparedEditors.Filename}; + end + end % TestMethodSetup + + methods(TestMethodTeardown) + function closeOpenedEditors_thenDeleteWorkingDir(testCase) + openEditors = matlab.desktop.editor.getAll; + for editor=openEditors(1:end) + if any(strcmp(editor.Filename, testCase.sparedEditors)) + continue; + end + % if not on our list, close the file + editor.close(); + end + end + end % TestMethodTeardown + + methods(Test) + + function SmokeRun(testCase,File) + + % Navigate to project root folder: + cd(testCase.RootFolder) + FileToRun = string(File); + + % Pre-test: + PreFiles = CheckPreFile(testCase,FileToRun); + run(PreFiles); + + % Run SmokeTest + disp(">> Running " + FileToRun); + try + run(fullfile("Scripts",FileToRun)); + catch ME + + end + + % Post-test: + PostFiles = CheckPostFile(testCase,FileToRun); + run(PostFiles) + + % Log every figure created during run: + Figures = findall(groot,'Type','figure'); + Figures = flipud(Figures); + if ~isempty(Figures) + for f = 1:size(Figures,1) + if ~isempty(Figures(f).Number) + FigDiag = matlab.unittest.diagnostics.FigureDiagnostic(Figures(f),'Formats','png'); + log(testCase,1,FigDiag); + end + end + end + + % Close all figures and Simulink models + close all force + if any(matlab.addons.installedAddons().Name == "Simulink") + bdclose all + end + + % Rethrow error if any + if exist("ME","var") + if ~any(strcmp(ME.identifier,KnownIssuesID)) + rethrow(ME) + end + end + + end + + end % Test Methods + + + methods (Access = private) + + function Path = CheckPreFile(testCase,Filename) + PreFile = "Pre"+replace(Filename,".mlx",".m"); + PreFilePath = fullfile(testCase.RootFolder,"SoftwareTests","PreFiles",PreFile); + if ~isfolder(fullfile(testCase.RootFolder,"SoftwareTests/PreFiles")) + mkdir(fullfile(testCase.RootFolder,"SoftwareTests/PreFiles")) + end + if ~isfile(PreFilePath) + writelines("% Pre-run script for "+Filename,PreFilePath) + writelines("% ---- Known Issues -----",PreFilePath,'WriteMode','append'); + writelines("KnownIssuesID = "+char(34)+char(34)+";",PreFilePath,'WriteMode','append'); + writelines("% ---- Pre-run commands -----",PreFilePath,'WriteMode','append'); + writelines(" ",PreFilePath,'WriteMode','append'); + end + Path = PreFilePath; + end + + function Path = CheckPostFile(testCase,Filename) + PostFile = "Post"+replace(Filename,".mlx",".m"); + PostFilePath = fullfile(testCase.RootFolder,"SoftwareTests","PostFiles",PostFile); + if ~isfolder(fullfile(testCase.RootFolder,"SoftwareTests/PostFiles")) + mkdir(fullfile(testCase.RootFolder,"SoftwareTests/PostFiles")) + end + if ~isfile(PostFilePath) + writelines("% Post-run script for "+Filename,PostFilePath) + writelines("% ---- Post-run commands -----",PostFilePath,'WriteMode','append'); + writelines(" ",PostFilePath,'WriteMode','append'); + end + Path = PostFilePath; + end + + end % Private Methods + +end % Smoketests \ No newline at end of file diff --git a/SoftwareTests/SolnSmokeTests.m b/SoftwareTests/SolnSmokeTests.m new file mode 100644 index 0000000..ec7b5a2 --- /dev/null +++ b/SoftwareTests/SolnSmokeTests.m @@ -0,0 +1,166 @@ +classdef SolnSmokeTests < matlab.unittest.TestCase + + properties + RootFolder + isSolnOnPath + sparedEditors % Track open files + end % properties + + properties (ClassSetupParameter) + Project = {currentProject()}; + end % ClassSetupParameter + + methods(TestMethodSetup) + function recordEditorsToSpare(testCase) + testCase.sparedEditors = matlab.desktop.editor.getAll; + testCase.sparedEditors = {testCase.sparedEditors.Filename}; + end + end % TestMethodSetup + + methods(TestMethodTeardown) + function closeOpenedEditors_thenDeleteWorkingDir(testCase) + openEditors = matlab.desktop.editor.getAll; + for editor=openEditors(1:end) + if any(strcmp(editor.Filename, testCase.sparedEditors)) + continue; + end + % if not on our list, close the file + editor.close(); + end + end + end % TestMethodTeardown + + properties (TestParameter) + File; + end % TestParameter + + methods (TestParameterDefinition,Static) + + function File = GetScriptName(Project) + % Retrieve student template files: + RootFolder = Project.RootFolder; + File = dir(fullfile(RootFolder,"Scripts","*.mlx")); + File = {File.name}; + end + + end % Static TestParameterDefinition + + methods (TestClassSetup) + + function SetUpPath(testCase,Project) + % Navigate to project root folder: + testCase.RootFolder = Project.RootFolder; + cd(testCase.RootFolder) + + % Check that solutions are on path: + testCase.isSolnOnPath = isfolder("Solutions"); + if testCase.isSolnOnPath == 0 + addpath(fullfile(testCase.RootFolder,"InstructorResources","Solutions")) + end + + % Close the StartUp app if still open: + delete(findall(groot,'Name','StartUp App')) + + % Log MATLAB version: + testCase.log("Running in " + version) + + end % function setUpPath + + end % methods (TestClassSetup) + + methods(Test) + + % Check that solutions files exist for each of the student + % templates + function ExistSolns(testCase,File) + SolutionName = replace(string(File),".mlx","Soln.mlx"); + assert(exist(SolutionName,"file"),"Missing solutions for "+File); + end + + + function SmokeRun(testCase,File) + + % Navigate to project root folder: + cd(testCase.RootFolder) + FileToRun = replace(string(File),".mlx","Soln.mlx"); + + % Pre-test: + PreFiles = CheckPreFile(testCase,FileToRun); + run(PreFiles); + + % Run SmokeTest + disp(">> Running " + FileToRun); + try + run(fullfile("InstructorResources","Solutions",FileToRun)); + catch ME + + end + + % Post-test: + PostFiles = CheckPostFile(testCase,FileToRun); + run(PostFiles) + + % Log every figure created during run: + Figures = findall(groot,'Type','figure'); + Figures = flipud(Figures); + if ~isempty(Figures) + for f = 1:size(Figures,1) + if ~isempty(Figures(f).Number) + FigDiag = matlab.unittest.diagnostics.FigureDiagnostic(Figures(f),'Formats','png'); + log(testCase,1,FigDiag); + end + end + end + + % Close all figures and Simulink models + close all force + if any(matlab.addons.installedAddons().Name == "Simulink") + bdclose all + end + + % Rethrow error if any + if exist("ME","var") + if ~any(strcmp(ME.identifier,KnownIssuesID)) + rethrow(ME) + end + end + + end + + end % Test Methods + + methods (Access = private) + + function Path = CheckPreFile(testCase,Filename) + PreFile = "Pre"+replace(Filename,".mlx",".m"); + PreFilePath = fullfile(testCase.RootFolder,"SoftwareTests","PreFiles",PreFile); + if ~isfolder(fullfile(testCase.RootFolder,"SoftwareTests/PreFiles")) + mkdir(fullfile(testCase.RootFolder,"SoftwareTests/PreFiles")) + end + if ~isfile(PreFilePath) + writelines("% Pre-run script for "+Filename,PreFilePath) + writelines("% ---- Known Issues -----",PreFilePath,'WriteMode','append'); + writelines("KnownIssuesID = "+char(34)+char(34)+";",PreFilePath,'WriteMode','append'); + writelines("% ---- Pre-run commands -----",PreFilePath,'WriteMode','append'); + writelines(" ",PreFilePath,'WriteMode','append'); + end + Path = PreFilePath; + end + + function Path = CheckPostFile(testCase,Filename) + PostFile = "Post"+replace(Filename,".mlx",".m"); + PostFilePath = fullfile(testCase.RootFolder,"SoftwareTests","PostFiles",PostFile); + if ~isfolder(fullfile(testCase.RootFolder,"SoftwareTests/PostFiles")) + mkdir(fullfile(testCase.RootFolder,"SoftwareTests/PostFiles")) + end + if ~isfile(PostFilePath) + writelines("% Post-run script for "+Filename,PostFilePath) + writelines("% ---- Post-run commands -----",PostFilePath,'WriteMode','append'); + writelines(" ",PostFilePath,'WriteMode','append'); + end + Path = PostFilePath; + end + + end % Private Access Methods + +end % SolnSmokeTests diff --git a/SoftwareTests/TestResults_R2024a.txt b/SoftwareTests/TestResults_R2024a.txt new file mode 100644 index 0000000..2cf7ade --- /dev/null +++ b/SoftwareTests/TestResults_R2024a.txt @@ -0,0 +1,12 @@ +Name,Passed,Failed,Incomplete,Duration,Details +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=Hand.mlx),1,0,0,0.0081279, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=ImplementExplicitSolver.mlx),1,0,0,3.4182225, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=Interpolation.mlx),1,0,0,27.383437, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=MeasureLakeArea.mlx),1,0,0,38.1402992, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalDerivatives.mlx),1,0,0,5.7204374, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalIntegration.mlx),1,0,0,11.6439181, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalODEs.mlx),1,0,0,9.5377586, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalPDEs.mlx),1,0,0,57.0697041, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=PendulumModels.mlx),1,0,0,3.8335752, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=TrackStorms.mlx),1,0,0,157.3072403, +FunctionTests[Project=0x0_char]/dataExists,1,0,0,0.0229859, diff --git a/SoftwareTests/TestResults_R2024b.txt b/SoftwareTests/TestResults_R2024b.txt new file mode 100644 index 0000000..7c84110 --- /dev/null +++ b/SoftwareTests/TestResults_R2024b.txt @@ -0,0 +1,12 @@ +Name,Passed,Failed,Incomplete,Duration,Details +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=Hand.mlx),1,0,0,1.0933756, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=ImplementExplicitSolver.mlx),1,0,0,0.0002897, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=Interpolation.mlx),1,0,0,0.0004386, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=MeasureLakeArea.mlx),1,0,0,26.1523377, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalDerivatives.mlx),1,0,0,0.0012912, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalIntegration.mlx),1,0,0,1.72e-05, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalODEs.mlx),1,0,0,9.6e-06, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=NumericalPDEs.mlx),1,0,0,7.9e-06, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=PendulumModels.mlx),1,0,0,0.0001478, +SmokeTests[Project=0x0_char]/SmokeRun(Scripts=TrackStorms.mlx),1,0,0,0.3293405, +FunctionTests[Project=0x0_char]/dataExists,1,0,0,0.0193367, diff --git a/SoftwareTests/model2t.m b/SoftwareTests/model2t.m deleted file mode 100644 index 8f0ed0e..0000000 --- a/SoftwareTests/model2t.m +++ /dev/null @@ -1,6 +0,0 @@ -function dydt = model2t(t,y,L,g) -theta = y(1); -omega = y(2); -dydt = [omega; ... - -g/L*sin(theta)]; -end \ No newline at end of file diff --git a/SoftwareTests/model3t.m b/SoftwareTests/model3t.m deleted file mode 100644 index 0bf07e4..0000000 --- a/SoftwareTests/model3t.m +++ /dev/null @@ -1,9 +0,0 @@ -function dydt = model3t(t,y,L,g,M,b,c) -theta = y(1); -omega = y(2); -if omega < 0 - c = -c; -end -dydt = [omega; ... - (-g*M*L*sin(theta)-b*omega-c*omega^2)/(M*L^2)]; -end \ No newline at end of file diff --git a/SoftwareTests/model4t.m b/SoftwareTests/model4t.m deleted file mode 100644 index c04a850..0000000 --- a/SoftwareTests/model4t.m +++ /dev/null @@ -1,10 +0,0 @@ -function dydt = model4t(t,y,L,g,M,m,b,c) -theta = y(1); -omega = y(2); -if omega < 0 - c = -c; -end -rotInertia = m*L^2/3+M*L^2; -dydt = [omega; ... - (-g*(M*L+m*L/2)*sin(theta)-b*omega-c*omega^2)/rotInertia]; -end \ No newline at end of file diff --git a/Utilities/OldVersions/MainMenuOld.mlx b/Utilities/OldVersions/MainMenuOld.mlx deleted file mode 100644 index 0b6a4ed..0000000 Binary files a/Utilities/OldVersions/MainMenuOld.mlx and /dev/null differ diff --git a/Utilities/OldVersions/READMEOld.mlx b/Utilities/OldVersions/READMEOld.mlx deleted file mode 100644 index a9af777..0000000 Binary files a/Utilities/OldVersions/READMEOld.mlx and /dev/null differ diff --git a/Utilities/ProjectSettings.mat b/Utilities/ProjectSettings.mat deleted file mode 100644 index 0679877..0000000 Binary files a/Utilities/ProjectSettings.mat and /dev/null differ diff --git a/Utilities/ProjectShutdown.m b/Utilities/ProjectShutdown.m index 6bfa816..323c6d6 100644 --- a/Utilities/ProjectShutdown.m +++ b/Utilities/ProjectShutdown.m @@ -1,69 +1,2 @@ -function ProjectShutdown -% Reset module to original state that is expected when loading in a new -% MATLAB version. -proj = currentProject; - -MoveFilesAround("R2023b","MainMenu.mlx",proj,Flag="Close") -MoveFilesAround("R2023b","README.mlx",proj,Flag="Close") -MoveFilesAround("R2024a","PendulumModels.mlx",proj,Flag="Close") -MoveFilesAround("R2023b","NumericalPDEs.mlx",proj,Flag="Close") - -% %% Example -% % To move ScriptName.mlx from a folder on the project path into -% % Utilities/OldVersions/ScriptName23b.mlx and replace it with -% % Utilities/OldVersions/ScriptName23a.mlx in the original location in the -% % project -% MoveFilesAround("R2024a","ScriptName.mlx",proj,OldStr="23b",NewStr="24a",Flag="Close") - -end - -function MoveFilesAround(ReleaseString,FileString,proj,opts) -arguments - ReleaseString (1,1) string {mustBeRelease} - FileString (1,1) string {mustLookLikeFile} - proj - opts.OldStr (1,1) string = "Old" - opts.NewStr (1,1) string = "New" - opts.Flag (1,1) string {mustBeMember(opts.Flag,["Open" "Close"])} = "Open" -end - -if ~contains(ReleaseString,"R") - ReleaseString = "R"+ReleaseString; -end -[FileLoc,FileName,FileExt] = fileparts(which(FileString)); - -if isMATLABReleaseOlderThan(ReleaseString) - FileStringOld = FileName+opts.OldStr+FileExt; - FileStringNew = FileName+opts.NewStr+FileExt; - FileString = string(FileName)+FileExt; - try - if opts.Flag == "Open" - if exist(fullfile(proj.RootFolder,"Utilities","OldVersions",FileStringOld),"file") - movefile(fullfile(FileLoc,FileString), fullfile("Utilities","OldVersions",FileStringNew)) - movefile(fullfile("Utilities","OldVersions",FileStringOld),fullfile(FileLoc,FileString)) - end - else - if exist(fullfile(proj.RootFolder,"Utilities","OldVersions",FileStringNew),"file") - movefile(fullfile(FileLoc,FileString), fullfile("Utilities","OldVersions",FileStringOld)) - movefile(fullfile("Utilities","OldVersions",FileStringNew),fullfile(FileLoc,FileString)) - end - end - catch - disp("Failed to move " + FileString + ".") - end -end -end - -function mustBeRelease(str) -if ~contains(str,"R") - str = "R"+str; -end -pattern = "R"+digitsPattern(4)+("a"|"b"); -assert(matches(str,pattern),"ReleaseString must be a valid MATLAB release.") -end - -function mustLookLikeFile(str) -[~,f,e] = fileparts(str); -assert(~isempty(f)) -assert(e==".mlx"|e==".m"|e==".slx") -end \ No newline at end of file +% Close the StartUp app if still open: +delete(findall(groot,'Name','StartUp App')) \ No newline at end of file diff --git a/Utilities/ProjectStartup.m b/Utilities/ProjectStartup.m deleted file mode 100644 index dc374fb..0000000 --- a/Utilities/ProjectStartup.m +++ /dev/null @@ -1,71 +0,0 @@ -function ProjectStartup -% Set up check for version number -proj = currentProject; - -% Address changes in the MATLAB language and capabilities -MoveFilesAround("R2023b","MainMenu.mlx",proj) -MoveFilesAround("R2023b","README.mlx",proj) -MoveFilesAround("R2024a","PendulumModels.mlx",proj) -MoveFilesAround("R2023b","NumericalPDEs.mlx",proj) - -% %% Example -% % To move ScriptName.mlx from a folder on the project path into -% % Utilities/OldVersions/ScriptName24a.mlx and replace it with -% % Utilities/OldVersions/ScriptName23b.mlx in the original location in the -% % project -% MoveFilesAround("R2024a","ScriptName.mlx",proj,OldStr="23b",NewStr="24a",Flag="Open") - -% Offer navigation aids and feedback opportunities -ProjectStartupApp -end - -function MoveFilesAround(ReleaseString,FileString,proj,opts) -arguments - ReleaseString (1,1) string {mustBeRelease} - FileString (1,1) string {mustLookLikeFile} - proj - opts.OldStr (1,1) string = "Old" - opts.NewStr (1,1) string = "New" - opts.Flag (1,1) string {mustBeMember(opts.Flag,["Open" "Close"])} = "Open" -end - -if ~contains(ReleaseString,"R") - ReleaseString = "R"+ReleaseString; -end -[FileLoc,FileName,FileExt] = fileparts(which(FileString)); - -if isMATLABReleaseOlderThan(ReleaseString) - FileStringOld = FileName+opts.OldStr+FileExt; - FileStringNew = FileName+opts.NewStr+FileExt; - FileString = string(FileName)+FileExt; - try - if opts.Flag == "Open" - if exist(fullfile(proj.RootFolder,"Utilities","OldVersions",FileStringOld),"file") - movefile(fullfile(FileLoc,FileString), fullfile("Utilities","OldVersions",FileStringNew)) - movefile(fullfile("Utilities","OldVersions",FileStringOld),fullfile(FileLoc,FileString)) - end - else - if exist(fullfile(proj.RootFolder,"Utilities","OldVersions",FileStringNew),"file") - movefile(fullfile(FileLoc,FileString), fullfile("Utilities","OldVersions",FileStringOld)) - movefile(fullfile("Utilities","OldVersions",FileStringNew),fullfile(FileLoc,FileString)) - end - end - catch - disp("Failed to move " + FileString + ".") - end -end -end - -function mustBeRelease(str) -if ~contains(str,"R") - str = "R"+str; -end -pattern = "R"+digitsPattern(4)+("a"|"b"); -assert(matches(str,pattern),"ReleaseString must be a valid MATLAB release.") -end - -function mustLookLikeFile(str) -[~,f,e] = fileparts(str); -assert(~isempty(f)) -assert(e==".mlx"|e==".m"|e==".slx") -end \ No newline at end of file diff --git a/Utilities/ProjectStartupApp.m b/Utilities/ProjectStartupApp.m index 1b723b0..87de875 100644 --- a/Utilities/ProjectStartupApp.m +++ b/Utilities/ProjectStartupApp.m @@ -2,29 +2,27 @@ % Properties that correspond to app components properties (Access = public) - UIFigure matlab.ui.Figure - TabGroup matlab.ui.container.TabGroup - WelcomeTab matlab.ui.container.Tab - Image matlab.ui.control.Image - READMEButton matlab.ui.control.Button - ReviewUsButton matlab.ui.control.Button - MainMenuButton matlab.ui.control.Button - WelcomeTitle matlab.ui.control.Label - TabReview matlab.ui.container.Tab - OtherButton matlab.ui.control.Button - StudentButton matlab.ui.control.Button - FacultyButton matlab.ui.control.Button - Q1 matlab.ui.control.Label - ReviewTitle matlab.ui.control.Label - ReviewText matlab.ui.control.Label + StartUpAppUIFigure matlab.ui.Figure + TabGroup matlab.ui.container.TabGroup + WelcomeTab matlab.ui.container.Tab + Image matlab.ui.control.Image + READMEButton matlab.ui.control.Button + ReviewUsButton matlab.ui.control.Button + MainMenuButton matlab.ui.control.Button + WelcomeTitle matlab.ui.control.Label + TabReview matlab.ui.container.Tab + OtherButton matlab.ui.control.Button + StudentButton matlab.ui.control.Button + FacultyButton matlab.ui.control.Button + Q1 matlab.ui.control.Label + ReviewTitle matlab.ui.control.Label + ReviewText matlab.ui.control.Label end properties (Access = private) GitHubOrganization = "MathWorks-Teaching-Resources"; % Description GitHubRepository = "Numerical-Methods-with-Applications"; - localForegroundColor - localBackgroundColor end %% How to customize the app? %{ @@ -99,31 +97,6 @@ function saveSettings(isReviewed,numLoad) % Code that executes after component creation function startupFcn(app) - app.localBackgroundColor = app.UIFigure.Color; - app.localForegroundColor = 1-app.localBackgroundColor; - if isMATLABReleaseOlderThan("R2024a") - hexBckgrndColor = app.localBackgroundColor; - else - hexBckgrndColor = rgb2hex(app.localBackgroundColor); - end - app.WelcomeTitle.FontColor = app.localForegroundColor; - app.READMEButton.FontColor = app.localForegroundColor; - app.READMEButton.BackgroundColor = hexBckgrndColor; - app.MainMenuButton.FontColor = app.localForegroundColor; - app.MainMenuButton.BackgroundColor = hexBckgrndColor; - app.ReviewUsButton.FontColor = app.localForegroundColor; - app.ReviewUsButton.BackgroundColor = hexBckgrndColor; - app.OtherButton.FontColor = app.localForegroundColor; - app.OtherButton.BackgroundColor = hexBckgrndColor; - app.StudentButton.FontColor = app.localForegroundColor; - app.StudentButton.BackgroundColor = hexBckgrndColor; - app.FacultyButton.FontColor = app.localForegroundColor; - app.FacultyButton.BackgroundColor = hexBckgrndColor; - app.ReviewTitle.FontColor = app.localForegroundColor; - app.ReviewText.FontColor = app.localForegroundColor; - - % Move gui to center of screen - movegui(app.UIFigure,"center") % Switch tab to review if has not been reviewed yet if isfile(fullfile("Utilities","ProjectSettings.mat")) @@ -156,14 +129,14 @@ function startupFcn(app) Request.Header = HeaderField("X-GitHub-Api-Version","2022-11-28"); Request.Header(2) = HeaderField("Accept","application/vnd.github+json"); [Answer,~,~] = send(Request,Address); - websave(fullfile("Utilities/SurveyLinks.mat"),Answer.Body.Data.download_url) + websave(fullfile("Utilities/SurveyLinks.mat"),Answer.Body.Data.download_url); catch end end - % Close request function: UIFigure - function UIFigureCloseRequest(app, event) + % Close request function: StartUpAppUIFigure + function StartUpAppUIFigureCloseRequest(app, event) if event.Source == app.READMEButton open README.mlx elseif event.Source == app.MainMenuButton @@ -182,28 +155,28 @@ function UIFigureCloseRequest(app, event) % Button pushed function: MainMenuButton function MainMenuButtonPushed(app, event) - UIFigureCloseRequest(app,event) + StartUpAppUIFigureCloseRequest(app,event) end % Button pushed function: FacultyButton function FacultyButtonPushed(app, event) app.pingSway; app.openFacultyForm; - UIFigureCloseRequest(app,event) + StartUpAppUIFigureCloseRequest(app,event) end % Button pushed function: StudentButton function StudentButtonPushed(app, event) app.pingSway; app.openStudentForm; - UIFigureCloseRequest(app,event) + StartUpAppUIFigureCloseRequest(app,event) end % Button pushed function: OtherButton function OtherButtonPushed(app, event) app.pingSway; app.openStudentForm; - UIFigureCloseRequest(app,event) + StartUpAppUIFigureCloseRequest(app,event) end % Button pushed function: ReviewUsButton @@ -213,7 +186,7 @@ function ReviewUsButtonPushed(app, event) % Button pushed function: READMEButton function READMEButtonPushed(app, event) - UIFigureCloseRequest(app,event) + StartUpAppUIFigureCloseRequest(app,event) end end @@ -223,16 +196,16 @@ function READMEButtonPushed(app, event) % Create UIFigure and components function createComponents(app) - % Create UIFigure and hide until all components are created - app.UIFigure = uifigure('Visible', 'off'); - app.UIFigure.AutoResizeChildren = 'off'; - app.UIFigure.Position = [100 100 276 460]; - app.UIFigure.Name = 'MATLAB App'; - app.UIFigure.Resize = 'off'; - app.UIFigure.CloseRequestFcn = createCallbackFcn(app, @UIFigureCloseRequest, true); + % Create StartUpAppUIFigure and hide until all components are created + app.StartUpAppUIFigure = uifigure('Visible', 'off'); + app.StartUpAppUIFigure.AutoResizeChildren = 'off'; + app.StartUpAppUIFigure.Position = [100 100 276 430]; + app.StartUpAppUIFigure.Name = 'StartUp App'; + app.StartUpAppUIFigure.Resize = 'off'; + app.StartUpAppUIFigure.CloseRequestFcn = createCallbackFcn(app, @StartUpAppUIFigureCloseRequest, true); % Create TabGroup - app.TabGroup = uitabgroup(app.UIFigure); + app.TabGroup = uitabgroup(app.StartUpAppUIFigure); app.TabGroup.AutoResizeChildren = 'off'; app.TabGroup.Position = [1 1 276 460]; @@ -248,34 +221,27 @@ function createComponents(app) app.WelcomeTitle.WordWrap = 'on'; app.WelcomeTitle.FontSize = 24; app.WelcomeTitle.FontWeight = 'bold'; - app.WelcomeTitle.FontColor = [0 0 0]; app.WelcomeTitle.Position = [2 349 274 70]; app.WelcomeTitle.Text = 'Numerical Methods with Applications'; % Create MainMenuButton app.MainMenuButton = uibutton(app.WelcomeTab, 'push'); app.MainMenuButton.ButtonPushedFcn = createCallbackFcn(app, @MainMenuButtonPushed, true); - app.MainMenuButton.BackgroundColor = [1 1 1]; app.MainMenuButton.FontSize = 18; - app.MainMenuButton.FontColor = [0 0 0]; app.MainMenuButton.Position = [59 96 161 35]; app.MainMenuButton.Text = 'Main Menu'; % Create ReviewUsButton app.ReviewUsButton = uibutton(app.WelcomeTab, 'push'); app.ReviewUsButton.ButtonPushedFcn = createCallbackFcn(app, @ReviewUsButtonPushed, true); - app.ReviewUsButton.BackgroundColor = [1 1 1]; app.ReviewUsButton.FontSize = 18; - app.ReviewUsButton.FontColor = [0 0 0]; app.ReviewUsButton.Position = [59 10 161 35]; app.ReviewUsButton.Text = 'Review Us'; % Create READMEButton app.READMEButton = uibutton(app.WelcomeTab, 'push'); app.READMEButton.ButtonPushedFcn = createCallbackFcn(app, @READMEButtonPushed, true); - app.READMEButton.BackgroundColor = [1 1 1]; app.READMEButton.FontSize = 18; - app.READMEButton.FontColor = [0 0 0]; app.READMEButton.Position = [59 53 161 35]; app.READMEButton.Text = 'README'; @@ -296,9 +262,8 @@ function createComponents(app) app.ReviewText.VerticalAlignment = 'top'; app.ReviewText.WordWrap = 'on'; app.ReviewText.FontSize = 18; - app.ReviewText.FontColor = [0 0 0]; app.ReviewText.Position = [16 243 245 69]; - app.ReviewText.Text = 'Plese help us improve your experience by answering a few questions.'; + app.ReviewText.Text = 'Please help us improve your experience by answering a few questions.'; % Create ReviewTitle app.ReviewTitle = uilabel(app.TabReview); @@ -307,9 +272,8 @@ function createComponents(app) app.ReviewTitle.WordWrap = 'on'; app.ReviewTitle.FontSize = 24; app.ReviewTitle.FontWeight = 'bold'; - app.ReviewTitle.FontColor = [0 0 0]; app.ReviewTitle.Position = [2 326 274 93]; - app.ReviewTitle.Text = 'Welcome to Numerical Methods with Applications'; + app.ReviewTitle.Text = 'Numerical Methods with Applications'; % Create Q1 app.Q1 = uilabel(app.TabReview); @@ -318,16 +282,13 @@ function createComponents(app) app.Q1.WordWrap = 'on'; app.Q1.FontSize = 18; app.Q1.FontWeight = 'bold'; - app.Q1.FontColor = [0 0 0]; app.Q1.Position = [16 141 245 69]; - app.Q1.Text = 'What describe you best?'; + app.Q1.Text = 'What describes you best?'; % Create FacultyButton app.FacultyButton = uibutton(app.TabReview, 'push'); app.FacultyButton.ButtonPushedFcn = createCallbackFcn(app, @FacultyButtonPushed, true); - app.FacultyButton.BackgroundColor = [0.149 0.149 0.149]; app.FacultyButton.FontSize = 18; - app.FacultyButton.FontColor = [0 0 0]; app.FacultyButton.Position = [64 127 150 40]; app.FacultyButton.Text = 'Faculty'; @@ -335,7 +296,6 @@ function createComponents(app) app.StudentButton = uibutton(app.TabReview, 'push'); app.StudentButton.ButtonPushedFcn = createCallbackFcn(app, @StudentButtonPushed, true); app.StudentButton.FontSize = 18; - app.StudentButton.FontColor = [0 0 0]; app.StudentButton.Position = [64 80 150 40]; app.StudentButton.Text = 'Student'; @@ -343,12 +303,11 @@ function createComponents(app) app.OtherButton = uibutton(app.TabReview, 'push'); app.OtherButton.ButtonPushedFcn = createCallbackFcn(app, @OtherButtonPushed, true); app.OtherButton.FontSize = 18; - app.OtherButton.FontColor = [0 0 0]; app.OtherButton.Position = [64 34 150 40]; app.OtherButton.Text = 'Other'; % Show the figure after all components are created - app.UIFigure.Visible = 'on'; + app.StartUpAppUIFigure.Visible = 'on'; end end @@ -362,7 +321,7 @@ function createComponents(app) createComponents(app) % Register the app with App Designer - registerApp(app, app.UIFigure) + registerApp(app, app.StartUpAppUIFigure) % Execute the startup function runStartupFcn(app, @startupFcn) @@ -376,7 +335,7 @@ function createComponents(app) function delete(app) % Delete UIFigure when app is deleted - delete(app.UIFigure) + delete(app.StartUpAppUIFigure) end end end \ No newline at end of file diff --git a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/uIYthjUuDNIiVXAl0s2ACeCA7XYd.xml b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/uIYthjUuDNIiVXAl0s2ACeCA7XYd.xml deleted file mode 100644 index 57d8832..0000000 --- a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/uIYthjUuDNIiVXAl0s2ACeCA7XYd.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/uIYthjUuDNIiVXAl0s2ACeCA7XYp.xml b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/uIYthjUuDNIiVXAl0s2ACeCA7XYp.xml deleted file mode 100644 index c132d44..0000000 --- a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/uIYthjUuDNIiVXAl0s2ACeCA7XYp.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/xcK8fO1pjra5DR0jot5vrzlBV84d.xml b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/xcK8fO1pjra5DR0jot5vrzlBV84d.xml index 50f7fa8..dc157b3 100644 --- a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/xcK8fO1pjra5DR0jot5vrzlBV84d.xml +++ b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/xcK8fO1pjra5DR0jot5vrzlBV84d.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/y8P_Fq2qJ6We-JIH8JyFmcTdT2wd.xml b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/y8P_Fq2qJ6We-JIH8JyFmcTdT2wd.xml new file mode 100644 index 0000000..31836f0 --- /dev/null +++ b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/y8P_Fq2qJ6We-JIH8JyFmcTdT2wd.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/y8P_Fq2qJ6We-JIH8JyFmcTdT2wp.xml b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/y8P_Fq2qJ6We-JIH8JyFmcTdT2wp.xml new file mode 100644 index 0000000..5ff9210 --- /dev/null +++ b/resources/project/KAXfQgCar2Yb8zOxgvf9hdmLP1E/y8P_Fq2qJ6We-JIH8JyFmcTdT2wp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/7iHV9hRFJ4wySENySofF6aAIHy0d.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/7iHV9hRFJ4wySENySofF6aAIHy0d.xml deleted file mode 100644 index 7a6326b..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/7iHV9hRFJ4wySENySofF6aAIHy0d.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/7iHV9hRFJ4wySENySofF6aAIHy0p.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/7iHV9hRFJ4wySENySofF6aAIHy0p.xml deleted file mode 100644 index ae8d7e9..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/7iHV9hRFJ4wySENySofF6aAIHy0p.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/EyDhXb-HjEIhAYfuSMUxquCH4aYd.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/EyDhXb-HjEIhAYfuSMUxquCH4aYd.xml deleted file mode 100644 index 7a6326b..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/EyDhXb-HjEIhAYfuSMUxquCH4aYd.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/EyDhXb-HjEIhAYfuSMUxquCH4aYp.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/EyDhXb-HjEIhAYfuSMUxquCH4aYp.xml deleted file mode 100644 index 173d9ab..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/EyDhXb-HjEIhAYfuSMUxquCH4aYp.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/dKAbbpX_L19F-VIpqXAxjLcumX0d.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/dKAbbpX_L19F-VIpqXAxjLcumX0d.xml deleted file mode 100644 index 7a6326b..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/dKAbbpX_L19F-VIpqXAxjLcumX0d.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/dKAbbpX_L19F-VIpqXAxjLcumX0p.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/dKAbbpX_L19F-VIpqXAxjLcumX0p.xml deleted file mode 100644 index a09a4f4..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/dKAbbpX_L19F-VIpqXAxjLcumX0p.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/swOs81E6yUqgBF1yHzvU3M7GvvAd.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/swOs81E6yUqgBF1yHzvU3M7GvvAd.xml deleted file mode 100644 index 7a6326b..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/swOs81E6yUqgBF1yHzvU3M7GvvAd.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/swOs81E6yUqgBF1yHzvU3M7GvvAp.xml b/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/swOs81E6yUqgBF1yHzvU3M7GvvAp.xml deleted file mode 100644 index efbdf31..0000000 --- a/resources/project/ZN2RlSIbyWXhOxbxxI4hOawbMD4/swOs81E6yUqgBF1yHzvU3M7GvvAp.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/resources/project/iMwdHOXOBiBXhnA_li8gtEJVTjc/nGmc4yUWSwVpS8w8tP7IolwQs0Ed.xml b/resources/project/iMwdHOXOBiBXhnA_li8gtEJVTjc/nGmc4yUWSwVpS8w8tP7IolwQs0Ed.xml deleted file mode 100644 index 7a6326b..0000000 --- a/resources/project/iMwdHOXOBiBXhnA_li8gtEJVTjc/nGmc4yUWSwVpS8w8tP7IolwQs0Ed.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/resources/project/iMwdHOXOBiBXhnA_li8gtEJVTjc/nGmc4yUWSwVpS8w8tP7IolwQs0Ep.xml b/resources/project/iMwdHOXOBiBXhnA_li8gtEJVTjc/nGmc4yUWSwVpS8w8tP7IolwQs0Ep.xml deleted file mode 100644 index 371b133..0000000 --- a/resources/project/iMwdHOXOBiBXhnA_li8gtEJVTjc/nGmc4yUWSwVpS8w8tP7IolwQs0Ep.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file