Solve a system of differential equations with ODE45 in Matlab - matlab

I need to solve a system of differential equations in a selected time span, but the equations depend on some variables that change with time. I'm trying to write the function 'odefun' to use in ode45, and when I run the code with the time span and initial conditions it seems to work, but I'm not sure if the code is actually doing what I want.
function [dX]=gauss(t,X)
mu_S=1.327*10^11; T=0.06; %constants
a=X(1); e=X(2);
n=sqrt(mu_S/a^3); M=n*t; %need to change with every iteration
[E] = KeplerPicard(M,e,0.5*10^-4);
dX(1)=2/n*sqrt((1+e*cos(E))/(1-e*cos(E)))*T; %da/dt
dX(2)=2*(1-e^2)*cos(E)/(a*n*sqrt(1-e^2*(cos(E))^2))*T; %de/dt
dX=dX(:);
end
dX(1) is the derivative of a, which is my X(1), and dX(2) is the derivative of e, X(2).
The function Kepler Picard is defined as follows:
function [E] = KeplerPicard(M,e,eps)
E=M;
err=1;
while err>eps
En=e*sin(E)+M;
err=abs(En-E);
E=En;
end
I want the variable 'n' to change during time and use the new value 'a+da' (or alternatively 'X(1)+dX(1)'), but I don't know if the code is doing this. It should be noted that this way the code runs without errors, but I don't know if the results are right (if the code sees 'n' as a constant, they're definitely wrong).
Is there something I need to change? Thanks!

Related

MATLAB Initial Objective Function Evaluation Error

I am trying to create a plot in MATLAB by iterating over values of a constant (A) with respect to a system of equations. My code is pasted below:
function F=Func1(X, A)
%X(1) is c
%X(2) is h
%X(3) is lambda
%A is technology (some constant)
%a is alpha
a=1;
F(1)=1/X(1)-X(3)
F(2)=X(3)*(X(1)-A*X(2)^a)
F(3)=-1/(24-X(2))-X(3)*A*a*X(2)^(a-1)
clear, clc
init_guess=[0,0,0]
for countA=1:0.01:10
result(countA,:)=[countA,fsolve(#Func1, init_guess)]
end
display('The Loop Has Ended')
display(result)
%plot(result(:,1),result(:,2))
The first set of code, I am defining the set of equations I am attempting to solve. In the second set of lines, I am trying to write a loop which iterates through the values of A that I want, [1,10] with an increment of 0.01. Right now, I am just trying to get my loop code to work, but I keep on getting this error:
"Failure in initial objective function evaluation. FSOLVE cannot continue."
I am not sure why this is the case. From what I understand, this is the result of my initial guess matrix not being the right size, but I believe it should be of size 3, as I am solving for three variables. Additionally, I'm fairly confident there's nothing wrong with how I'm referencing my Func1 code in my Loop code.
Any advice you all could provide would be sincerely appreciated. I've only been working on MATLAB for a few days, so if this is a rather trivial fix, pardon my ignorance. Thanks.
Couple of issues with your code:
1/X(1) in function Func1 is prone to the division by zero miscalculations. I would change it to 1/(X(1)+eps).
If countA is incrementing by 0.01, it cannot be used as an index for result. Perhaps introduce an index ind to increment.
I have included your constant A within the function to clarify what optimization variables are.
Here is the updated code. I don't know if the results are reasonable or not:
init_guess=[0,0,0];
ind = 1;
for countA=1:0.01:10
result(ind,:)=[countA, fsolve(#(X) Func1(X,countA), init_guess)];
ind = ind+1;
end
display('The Loop Has Ended')
display(result)
%plot(result(:,1),result(:,2))
function F=Func1(X,A)
%X(1) is c
%X(2) is h
%X(3) is lambda
%A is technology (some constant)
%a is alpha
a=1;
F(1)=1/(X(1)+eps)-X(3);
F(2)=X(3)*(X(1)-A*X(2)^a);
F(3)=-1/(24-X(2))-X(3)*A*a*X(2)^(a-1);
end

General Newton Method Function File Matlab

I have very limited knowledge on Matlab and I'm trying to make a general Newton Raphson function but every time it comes up with an error saying there are not enough input arguments. My code needs three inputs, f (the function), c0 (the initial guess) and n (the number of steps). This is my code so far:
function [c] = Q3(f,c0,n)
for i=1:n
c(0)=c0;
f=f(x);
fp=diff(f,x);
c(i)=c(i-1)-subs(f,x,c(i-1))/subs(fp,c(i-1));
end
disp(c)
I have this function written in a script file
g=#(x)(sin((pi.*x)/2)+(1/x)-(10.*x));
I then put this into the command window [c]=Q3(g(x),1,n) hoping it would work but obviously my code needs work.
Thanks
This should do the trick, the function g is defined as you stated:
g=#(x)(sin((pi.*x)/2)+(1/x)-(10.*x));
but also you should define n and c0, for example:
clearvars
g=#(x)(sin((pi.*x)/2)+(1/x)-(10.*x));
n=10
c0=1
c=Q3(g,c0,n)
And in another file you write the function for NR:
function [c] = Q3(f,c0,n)
h=1e-4;
c(1)=c0;
for i=1:n
g=f(c(i));
gp=(f(c(i)+h)-f(c(i)-h))/(2*h)
c(i+1)=c(i)-g/gp
end
disp(c)
In this case I choose h=1e-4 for the numerical derivative approximation, but you can change it. I suggest h<1e-2.

How do I run the Initial value x0 also in parallel

This code works fine but the plot is not correct because the optimization function fmincon will depend on the initial condition x0 and the number of iterations. For each value of alpha (a) and beta (b), I should run the optimization many times with different initial conditions x0 to verify that I am getting the right answer. More iterations might be required to get an accurate answer.
I want to be able to run the optimization with different initial conditions for x0, a and b.
Function file
function f = threestate2(x,a,b)
c1 = cos(x(1))*(cos(x(5))*(cos(x(9))+cos(x(11)))+cos(x(7))*(cos(x(9))-cos(x(11))))...
+cos(x(3))*(cos(x(5))*(cos(x(9))-cos(x(11)))-cos(x(7))*(cos(x(9))+cos(x(11))));
c2=sin(x(1))*(sin(x(5))*(sin(x(9))*cos(x(2)+x(6)+x(10))+sin(x(11))*cos(x(2)+x(6)+x(12)))...
+sin(x(7))*(sin(x(9))*cos(x(2)+x(8)+x(10))-sin(x(11))*cos(x(2)+x(8)+x(12))))...
+sin(x(3))*(sin(x(5))*(sin(x(9))*cos(x(4)+x(6)+x(10))-sin(x(11))*cos(x(4)+x(6)+x(12)))...
-sin(x(7))*(sin(x(9))*cos(x(4)+x(8)+x(10))+sin(x(11))*cos(x(4)+x(8)+x(12))));
f=(a*a-b*b)*c1+2*a*b*c2;
Main file
%x=[x(1),x(2),x(3),x(4),x(5),x(6),x(7),x(8),x(9),x(10),x(11),x(12)]; % angles;
lb=[0,0,0,0,0,0,0,0,0,0,0,0];
ub=[pi,2*pi,pi,2*pi,pi,2*pi,pi,2*pi,pi,2*pi,pi,2*pi];
x0=[pi/8;0;pi/3;0;0.7*pi;.6;0;pi/2;.5;0;pi/4;0];
xout=[];
fout=[];
options = optimoptions(#fmincon,'Algorithm','interior-point','TolX',10^-10,'MaxIter',1500);
a=0:0.01:1;
w=NaN(length(a));
for i=1:length(a)
bhelp=(1-a(i)*a(i));
if bhelp>0
b=sqrt(bhelp);
[x,fval]=fmincon(#(x)threestate2(x,a(i),b),x0,[],[],[],[],lb,ub,[],options);
w(i)=fval;
w(i)=-w(i);
B(i)=b;
else
w(i)=NaN;
B(i)=b;
end
end
%surface(b,a,w)
%view(3)
%meshc(b,a,w)
x=a.^2;
plot(x,w)
grid on
ylabel('\fontname{Times New Roman} S_{max}(\Psi_{gs})')
xlabel('\fontname{Times New Roman}\alpha^2')
%ylabel('\fontname{Times New Roman}\beta')
title('\fontname{Times New Roman} Maximum of the Svetlichny operator(\alpha|000>+\beta|111>)')
If you have the Matlab Parallel Toolbox, you can use the parfor which is like a regular loop but runs in parallel.
To use it you should make your all big messy script in a function. Assuming you store your initial conditions in A(i) and you store the results in B(i) you can use something like that:
parfor i=1:length(B)
B(i)=optimise(A(i));
end
If you don't have the toolbox there are some other ways (for example MEX files) but you basically have to manage the threads yourself so I wouldn't recommend it.

matlab for loop within ode solver

i am using ODE solver for solving my system of ODE. Now i also want to calculate sensitivity of various parameters by varying them.
My basic ODE solver program is something like:
Function:
function F = ODE_site(t,y)
%%Parameter block
k1f=1e8;
k1b=1e5; %%and so on
%%Elementary rate block
r1=k1f*y(1)-k1b*P*y(5);
and so on
%%Mass balance block
F=[ r1-r5-r78+r86 ;
and so on ];
%% End of function
The main ODE solver looks like:
optode = odeset('NonNegative',1:41,'Abstol',1E-20,'RelTol',1E-20);
y0=zeros(41,1);
y0(41) = 1;
[t,y]=ode15s(#ODE_site,[0,50000000000],y0,optode);
%% Plus some other lines to plot the solution
%% End of ODE solver
Now, I want to introduce a for loop in the main solver but the problem is if i use for loop in the main solver, it cannot pass the command to the function. I tried to use global to assign the variable to all over the environment but it didn't work. How can i assign the for loop for both the ODE solver code and function?
Any help will be highly appreciated.
Thanks,
Mamun
Define the parameters, which you want to modify as addional input parameter to the function:
function F = ODE_site(t,y,param)
%%Parameter block
k1f=param(1);
k1b=param(2); %%and so on
%%Elementary rate block
r1=k1f*y(1)-k1b*P*y(5);
and so on
%%Mass balance block
F=[ r1-r5-r78+r86 ;
and so on ];
%% End of function
You can hand over the parameters to your function in ode15() after the optimisation Parameters:
optode = odeset('NonNegative',1:41,'Abstol',1E-20,'RelTol',1E-20);
y0=zeros(41,1);
y0(41) = 1;
para=[1e5, 1e8]
[t,y]=ode15s(#ODE_site,[0,50000000000],y0,optode,para);
Two notes:
*) Code is untested. Since your example was not executable I didn't care to make a running example too.
*) It looks like you are solving chemical reaction kinetics. Most likely you could further optimize your code by using matrix and vector operations.
So instead of usning separate variables r1, r2, r3, .. you could store it in one vector r(1), r(2), r(3), ...
Your last line, than could be written by the product of the reaction vector with the stoechiometric matrix.

Can I change the formula of a symbolic function in MATLAB?

I have the following code:
syms t x;
e=symfun(x-t,[x,t]);
In the problem I want to solve x is a function of t but I only know its value at the given t,so I modeled it here as a variable.I want to differentiate e with respect to time without "losing" x,so that I can then substitute it with x'(t) which is known to me.
In another question of mine here,someone suggested that I write the following:
e=symfun(exp(t)-t,[t]);
and after the differentiation check if I can substitute exp(t) with the value of x'(t).
Is this possible?Is there any other neater way?
I'm really not sure I understand what you're asking (and I didn't understand your other question either), but here's an attempt.
Since, x is a function of time, let's make that explicit by making it what the help and documentation for symfun calls an "abstract" or "arbitrary" symbolic function, i.e., one without a definition. In Matlab R2014b:
syms t x(t);
e = symfun(x-t,t)
which returns
e(t) =
x(t) - t
Taking the derivative of the symfun function e with respect to time:
edot = diff(e,t)
returns
edot(t) =
D(x)(t) - 1
the expression for edot(t) is a function of the derivative of x with respect to time:
xdot = diff(x,t)
which is the abstract symfun:
xdot(t) =
D(x)(t)
Now, I think you want to be able to substitute a specific value for xdot (xdot_given) into e(t) for t at t_given. You should be able to do this just using subs, e.g., something like this:
sums t_given xdot_given;
edot_t_given = subs(edot,{t,xdot},{t_given, xdot_given});
You may not need to substitute t if the only parts of edot that are a function of time are the xdot parts.