Beautifying RK4Automatic.m

This commit is contained in:
PolishPigeon 2022-01-08 03:24:09 +01:00
parent cb42f561f5
commit 3ae8bd014c
8 changed files with 217 additions and 31 deletions

View File

@ -1,8 +1,8 @@
% solve ODE system using RK4 with constant step size
function [x, derivativesTable] = rk4(functions, initialValues, interval, stepSize, maxSteps)
function [x, derivativesTable] = RK4(equations, initialValues, interval, stepSize, maxSteps)
x = initialValues;
derivativesTable = buildDerivatiesTable(x, functions);
derivativesTable = buildDerivatiesTable(x, equations);
% Calculate stepCount
stepCount = ceil((interval(2) - interval(1)) / stepSize);
@ -13,35 +13,37 @@ function [x, derivativesTable] = rk4(functions, initialValues, interval, stepSiz
% then choose smaller number between maxSteps and stepCount and choose
% it for stepCount
[x, derivativesTable] = rk4Loop(x, stepCount, stepSize, functions, derivativesTable);
[x, derivativesTable] = rk4Loop(x, stepCount, stepSize, equations, derivativesTable);
% append arguments to output
x = [interval(1):stepSize:(stepCount * stepSize); x];
end
function derivativesTable = buildDerivatiesTable(x, functions)
function derivativesTable = buildDerivatiesTable(x, equations)
derivativesTable = zeros(size(x));
for eqnum = 1:size(functions, 1)
derivativesTable(eqnum, 1) = functions{eqnum}(x(:, 1));
for eqnum = 1:size(equations, 1)
derivativesTable(eqnum, 1) = equations{eqnum}(x(:, 1));
end
end
function [x, derivativesTable] = rk4Loop(x, stepCount, stepSize, functions, derivativesTable)
function [x, derivativesTable] = rk4Loop(x, stepCount, stepSize, equations, derivativesTable)
for step = 1 : stepCount
[x, derivativesTable] = rk4stepLoop(x, step, functions, stepSize, derivativesTable);
[x, derivativesTable] = rk4stepLoop(x, step, equations, stepSize, derivativesTable);
end
end
function [x, derivativesTable] = rk4stepLoop(x, step, functions, stepSize, derivativesTable)
function [x, derivativesTable] = rk4stepLoop(x, step, equations, stepSize, derivativesTable)
stepValue = x(:, step);
[x, derivativesTable] = equationsLoop(x, equations, stepValue, stepSize, step, derivativesTable);
end
function [x, derivativesTable] = equationsLoop(x, equations, stepValue, stepSize, step, derivativesTable)
for equationNumber = 1 : 2
% generic single-step iteration
phi = RK4Phi(functions{equationNumber}, stepValue, stepSize);
x(equationNumber, step + 1) = x(equationNumber, step) + stepSize * phi;
Phi = RK4Phi(equations{equationNumber}, stepValue, stepSize);
x(equationNumber, step + 1) = x(equationNumber, step) + stepSize * Phi;
% update derivatives table
derivativesTable(equationNumber, step + 1) = functions{equationNumber}(x(:, step + 1));
derivativesTable(equationNumber, step + 1) = equations{equationNumber}(x(:, step + 1));
end
end

View File

@ -0,0 +1,92 @@
% automatic step size variant of RK4
function [x, sizes, errors] = RK4Automatic(equations, initialValues, interval, initialStepSize, relativeEpsilon, absoluteEpsilon)
[functionArguments, x, sizes, errors, stepSize, step, flag] = Initialize(interval, initialValues, initialStepSize);
[functionArguments, x, sizes, errors] = RK4AutomaticLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag);
% append arguments to output
x = [functionArguments; x];
end
function [functionArguments, x, sizes, errors, stepSize, step, flag] = Initialize(interval, initialValues, initialStepSize)
functionArguments = interval(1);
x = initialValues;
sizes = double.empty();
errors = double.empty();
stepSize = initialStepSize;
step = 0;
flag = 1;
end
function [functionArguments, x, sizes, errors] = RK4AutomaticLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag)
while flag
[functionArguments, x, sizes, errors, stepSize, step, interval, flag] = insideWhileLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag);
end
end
function [functionArguments, x, sizes, errors, stepSize, step, interval, flag] = insideWhileLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag)
[step, stepValue] = initializeSteps(step, x);
x = equationsLoop(x, equations, stepValue, stepSize, step);
[flag, functionArguments] = stopAlgorithm(functionArguments, stepSize, step, interval);
if ~flag
return;
end
stepValue = calculateNextStep(equations, stepValue, stepSize);
[stepCorrectionFactor, errors] = calculateStepCorrection(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors);
stepSize = 0.9 * stepCorrectionFactor * stepSize;
sizes(step) = stepSize;
end
function v
function [step, stepValue] = initializeSteps(step, x)
step = step + 1;
stepValue = x(:, step);
end
function x = equationsLoop(x, equations, stepValue, stepSize, step)
for equationNumber = 1 : 2
Phi = RK4Phi(equations{equationNumber}, stepValue, stepSize);
x(equationNumber, step + 1) = x(equationNumber, step) + stepSize * Phi;
end
end
function [flag, functionArguments] = stopAlgorithm(functionArguments, stepSize, step, interval)
functionArguments(step + 1) = functionArguments(step) + stepSize;
if functionArguments(end) >= interval(2)
flag = 0;
else
flag = 1;
end
end
function stepValue = calculateNextStep(equations, stepValue, stepSize)
for halfStep = 1 : 2
for equationsNumber = 1:size(equations, 1)
Phi = RK4Phi(equations{equationsNumber}, stepValue, stepSize / 2);
stepValue(equationsNumber) = stepValue(equationsNumber) + (stepSize / 2) * Phi;
end
end
end
function [stepCorrectionFactor, errors] = calculateStepCorrection(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors)
stepCorrectionFactor = Inf; % Initialize stepCorrectionFactor
[stepCorrectionFactor, errors] = calculateStepCorrectionLoop(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors, stepCorrectionFactor);
stepCorrectionFactor = stepCorrectionFactor ^ (1/5);
end
function [stepCorrectionFactor, errors] = calculateStepCorrectionLoop(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors, stepCorrectionFactor)
for equationsNumber = 1 : 2
approximationError = abs(stepValue(equationsNumber) - x(equationsNumber, step + 1)) / 15;
errors(step) = approximationError;
epsilon = abs(stepValue(equationsNumber)) * relativeEpsilon + absoluteEpsilon;
equationAlpha = epsilon / approximationError;
if equationAlpha < stepCorrectionFactor
stepCorrectionFactor = equationAlpha;
end
end
end

View File

@ -0,0 +1,96 @@
function [x, sizes, errors] = RK4Automatic(equations, initialValues, interval, initialStepSize, relativeEpsilon, absoluteEpsilon)
[functionArguments, x, sizes, errors, stepSize, step, flag] = Initialize(interval, initialValues, initialStepSize);
[functionArguments, x, sizes, errors] = RK4AutomaticLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag);
x = [functionArguments; x];
end
function [functionArguments, x, sizes, errors, stepSize, step, flag] = Initialize(interval, initialValues, initialStepSize)
functionArguments = interval(1);
x = initialValues;
sizes = double.empty();
errors = double.empty();
stepSize = initialStepSize;
step = 0;
flag = 1;
end
function [functionArguments, x, sizes, errors] = RK4AutomaticLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag)
while flag
[functionArguments, x, sizes, errors, stepSize, step, interval, flag] = insideWhileLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag);
end
end
function [functionArguments, x, sizes, errors, stepSize, step, interval, flag] = insideWhileLoop(functionArguments, x, sizes, errors, stepSize, step, equations, relativeEpsilon, absoluteEpsilon, interval, flag)
[step, stepValue, x, functionArguments, flag] = calculateXandFunctionArguments(step, x, equations, stepSize, functionArguments, interval);
if ~flag
return;
end
[stepSize, errors] = calculateStepAndErrors(equations, stepValue, stepSize, x, step, relativeEpsilon, absoluteEpsilon, errors);
sizes(step) = stepSize;
end
function [step, stepValue, x, functionArguments, flag] = calculateXandFunctionArguments(step, x, equations, stepSize, functionArguments, interval)
[step, stepValue] = initializeSteps(step, x);
x = equationsLoop(x, equations, stepValue, stepSize, step);
[flag, functionArguments] = stopAlgorithm(functionArguments, stepSize, step, interval);
end
function [stepSize, errors] = calculateStepAndErrors(equations, stepValue, stepSize, x, step, relativeEpsilon, absoluteEpsilon, errors)
stepValue = calculateNextStep(equations, stepValue, stepSize);
[stepCorrectionFactor, errors] = calculateStepCorrection(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors);
stepSize = 0.9 * stepCorrectionFactor * stepSize;
end
function [step, stepValue] = initializeSteps(step, x)
step = step + 1;
stepValue = x(:, step);
end
function x = equationsLoop(x, equations, stepValue, stepSize, step)
for equationNumber = 1 : 2
Phi = RK4Phi(equations{equationNumber}, stepValue, stepSize);
x(equationNumber, step + 1) = x(equationNumber, step) + stepSize * Phi;
end
end
function [flag, functionArguments] = stopAlgorithm(functionArguments, stepSize, step, interval)
functionArguments(step + 1) = functionArguments(step) + stepSize;
if functionArguments(end) >= interval(2)
flag = 0;
else
flag = 1;
end
end
function stepValue = calculateNextStep(equations, stepValue, stepSize)
for halfStep = 1 : 2
for equationsNumber = 1:size(equations, 1)
Phi = RK4Phi(equations{equationsNumber}, stepValue, stepSize / 2);
stepValue(equationsNumber) = stepValue(equationsNumber) + (stepSize / 2) * Phi;
end
end
end
function [stepCorrectionFactor, errors] = calculateStepCorrection(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors)
stepCorrectionFactor = Inf; % Initialize stepCorrectionFactor
[stepCorrectionFactor, errors] = calculateStepCorrectionLoop(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors, stepCorrectionFactor);
stepCorrectionFactor = stepCorrectionFactor ^ (1/5);
end
function [stepCorrectionFactor, errors] = calculateStepCorrectionLoop(stepValue, x, step, relativeEpsilon, absoluteEpsilon, errors, stepCorrectionFactor)
for equationsNumber = 1 : 2
approximationError = abs(stepValue(equationsNumber) - x(equationsNumber, step + 1)) / 15;
errors(step) = approximationError;
epsilon = abs(stepValue(equationsNumber)) * relativeEpsilon + absoluteEpsilon;
equationAlpha = epsilon / approximationError;
if equationAlpha < stepCorrectionFactor
stepCorrectionFactor = equationAlpha;
end
end
end

View File

@ -1,7 +1,3 @@
% ENUME MICHAŁ SZOPIŃSKI
% PROJECT C NUMBER 60
% https://github.com/Lachcim/szopinski-enume
% coordinate arguments
argsx = -1:0.1:1;
argsy = -2:0.5:12;

View File

View File

@ -1,5 +1,5 @@
% solve ODE system using RK4 with constant step size
function [x, derivativesTable] = rk4(equations, initialValues, interval, stepSize, maxSteps)
function [x, derivativesTable] = RK4(equations, initialValues, interval, stepSize, maxSteps)
x = initialValues;
derivativesTable = buildDerivatiesTable(x, equations);

View File

@ -1,15 +1,15 @@
% automatic step size variant of RK4
function [x, sizes, errors] = rk4auto(functs, init, interval, initstep, eps_rel, eps_abs)
function [x, sizes, errors] = RK4Automatic(equations, initialValues, interval, initialStepSize, relativeEpsilon, absoluteEpsilon)
% set start points of output
args = interval(1);
x = init;
x = initialValues;
% initialize output plots
sizes = double.empty();
errors = double.empty();
% integrate function until end of interval reached
stepsize = initstep;
stepsize = initialStepSize;
step = 0;
while 1
% obtain the preceding function values
@ -17,9 +17,9 @@ function [x, sizes, errors] = rk4auto(functs, init, interval, initstep, eps_rel,
stepval = x(:, step);
% advance output function
for eqnum = 1:size(functs, 1)
for eqnum = 1:size(equations, 1)
% generic single-step iteration
phi = RK4Phi(functs{eqnum}, stepval, stepsize);
phi = RK4Phi(equations{eqnum}, stepval, stepsize);
x(eqnum, step + 1) = x(eqnum, step) + stepsize * phi;
end
@ -29,21 +29,21 @@ function [x, sizes, errors] = rk4auto(functs, init, interval, initstep, eps_rel,
% also calculate next step using two half-steps
for substep = 1:2
for eqnum = 1:size(functs, 1)
phi = RK4Phi(functs{eqnum}, stepval, stepsize / 2);
for eqnum = 1:size(equations, 1)
phi = RK4Phi(equations{eqnum}, stepval, stepsize / 2);
stepval(eqnum) = stepval(eqnum) + (stepsize / 2) * phi;
end
end
% calculate step correction factor
alpha = Inf;
for eqnum = 1:size(functs, 1)
for eqnum = 1:size(equations, 1)
% calculate approximation error
delta = abs(stepval(eqnum) - x(eqnum, step + 1)) / 15;
errors(step) = delta;
% calculate equation-specific alpha
epsilon = abs(stepval(eqnum)) * eps_rel + eps_abs;
epsilon = abs(stepval(eqnum)) * relativeEpsilon + absoluteEpsilon;
eqalpha = epsilon / delta;
% minimum alpha wins

View File

@ -8,7 +8,7 @@ interval = [0; 15];
% define available algorithms
algorithms = {
'RK4', @rk4, [0.01, 0.013408];
'RK4', @RK4, [0.01, 0.013408];
'Adams PC', @adamspc, [0.002, 0.01305]
};
@ -59,7 +59,7 @@ for alg = 1 : 2
end
% solve ODE using RK4 with automatic step size
[result, sizes, errors] = rk4auto(sysfuncts, initvalues, interval, ...
[result, sizes, errors] = RK4Automatic(sysfuncts, initvalues, interval, ...
1e-5, 10e-10, 10e-10);
% plot trajectory