matlab for loop within ode solver - matlab

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.

Related

How to force dde23 function to generate output after fixed time step

I am solving a delay differential equation using MATLAB dde23 function. I want to use the output generated by the first dde23 function in the second dde23 function. Here is the code
tspan=[0:1:1440]';
x0=1.7;
%1st function
% options = ddeset('OutputFcn',#odeplot,'OutputSel',1);
sol = dde23(#dd,70,x0,tspan,options);
y_obs=sol.y;
tspan_new=sol.x;
%{2nd function
x1=[x0 ; 0.1; 0.01; 0.01];
final_sol = dde23(#ddc,70,x1,tspan,[],y_obs);
y_fit=final_sol.y;
tdata=final_sol.x;
%}
The time series I generated as an input to the first function is of size 1441 but the size of tspan_new and y_obs is 212 (generated from the dde23 output). I am unable to understand why the size is changing.
Is it possible to output y_obs at each time point provided in the input i.e. is it possible to obtain y_obs of length 1441 in this case ?
Since the size of output is different I am unable to use y_obs vector in my second function. The size of y_fit and tdata is again entirely different from y_obs and tspan.
Unlike the ODE Suite that implements a dense output routine as part of its time march, dde23 requires an explicit post-deval to accomplish what you're after:
tspan=[0:1:1440]';
x0=1.7;
%1st function
sol = dde23(#dd,70,x0,tspan([1,end]),options);
y_obs = deval(sol,tspan);
This function uses local Hermite cubic interpolation on the mesh generated by its dynamic time-stepping routine to approximate the y value at the requested t values.

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.

Constrain optimization in MATLAB for cost function which have extra parameter passing to it

I'm an electrical engineer who not familiar with MATLAB. My question is how can I pass other variable that use for calculate cost function when I call "fmincon"command. First I start with making a cost function name "Sum_Square_error.m" for calculate sum square error from estimated output (output that estimate from using Neural network) and real output.In this function I will use weight from welled train network multiply with shrinkage coefficient matrix(c) and call it "modify_input_weight". Then I evaluate neural network with modify_input_weight.So I get the estimate output. After that I get sum square error. My objective is to minimize Sum_square_error by adjust weight of neural network by using shrinkage coefficient matrix(c).
I have already read "fmincon" function reference. I can passing extra parameter for by three method
1. Anonymous Functions
2. Nested Functions
3. Global Variables
For this kind of problem which method is best fit. I tried to use Anonymous Functions like this
------------------------------------------- Sum_Square_error.m -------------------------------------------------------
f = #(c) Sum_Square_error(c,input_weight,X_test,Y_test);
for i=1:10
modify_input_weight(:,i) = c(i,1)*input_weight(:,i);
end
net.IW{1,1}= modify_input_weight;
y = net(X_test);
e = gsubtract(Y_test,y);
f = sum(e)^2;
end
-------------------------------------------------- Main program ----------------------------------------------------------
A = ones(1,10);
b = s;
lb = zeros(1,10);
[c,fval] = fmincon(#Sum_Square_error,c0,A,b,[],[],lb,[]);
but after I tried to run this program, it show many error message. Could someone please help me to passing "c,input_weight,X_test,Y_test" to optimize this cost function.
in Sum_Square_error.m you dont declare an anonymous function make it a regular function so change
f = #(c) Sum_Square_error(c,input_weight,X_test,Y_test);
to
function f = Sum_Square_error(c,input_weight,X_test,Y_test)
now in your main, when you say #fun you actually need to pass in the paremeters explicitly
fmincon(#Sum_Square_error(c,input_Weight,X_test,Y_test),c0,A,b,[],[],lb,[]);
where you replace c,input_Weight,X_test,Y_test with actual data

Errors when using functions with multiple inputs

I am trying to evaluate a duffing oscillator in MATLAB with multiple inputs, and I am getting an odd error I was hoping someone might be able to help me with.
Here is the code:
% file duffing.m
function dy=duffing(t,y,a,b,d,g,w)
dy=[y(2); -a*y(1)^3-b*y(1)-d*y(2)+g*cos(w*t)];
end
And the file that calls the duffing function:
t=0:0.01:100;
%duffing oscillator
y0=[2,0];
a=1;
b=-1;
d=0.2;
w=1;
g=0.1;
% duffing oscillator
[t,y]=ode45('duffing',t,y0,a,b,d,g,w);
When I run it, I get the following error:
Error using odearguments (line 92)
DUFFING returns a vector of length 1, but the length of initial conditions vector is 2. The vector returned by DUFFING and the initial conditions vector must have the same number of elements.
But when I define the function duffing as
function dy=duffing(t,y)
a=1;
b=-1;
d=0.2;
w=1;
dy=[y(2); -a*y(1)^3-b*y(1)-d*y(2)+g*cos(w*t)];
end
and pass in
[t y]=ode45('duffing',t,y0);
with the same y0 as above, it runs fine and I can plot it.
What am I doing wrong?
ode45 takes as input a function of two variables only. If you want to pass more inputs, you have to create a little anonymous function, like this:
a=1;
b=-1;
d=0.2;
w=1;
g=0.1;
% duffing oscillator
[t,y]=ode45(#(t,y) duffing(t,y,a,b,d,g,w),t,y0);
The syntax for ode45 is:
function varargout = ode45(ode,tspan,y0,options,varargin)
The fourth argument, options, is an options struct created with odeset. The additional inputs need to be the fifth and later, and the function needs to be modified. The official way is to use a function handle or global variables, but here's how to do it with arguments to ode45.
options = odeset('RelTol',1e-4);
[t,y]=ode45('duffing',t,y0,options,a,b,d,g,w);
Then you have to modify duffing with a dummy argument to be compatible with the calling convention of odearguments.m (f(t,y,'',p1,p2...)):
function dy=duffing(t,y,~,a,b,d,g,w)
dy=[y(2); -a*y(1)^3-b*y(1)-d*y(2)+g*cos(w*t)];
end
The official function handle solution looks something like this:
myDuffing = #(t,y) duffing(t,y,a,b,d,g,w);
Then call ode45 the same way as your second approach, but with myDuffing (see David's solution for this method).

Matlab ODE45. How to change a function inside it while calling it?

The functions w_d(Y,T) and q(tg,tm) are being used in a function called by the ODE solver described below:
function dPdh=gasstep1(~,P)
global rho_solid W_B S e height_dryer c_a c_b tm_o
dPdh=zeros(size(P));
Y=P(1);tg=P(2);
% Mass Balance
dPdh(1)=rho_solid*(1-e)*S*height_dryer/W_B*w_d(Y,tg);
% Enthalpy balance
dPdh(2)=-rho_solid*(1-e)*S*height_dryer/W_B*(1/(c_b+c_a*Y))...
*(q(tg,tm_o)+(c_a*(tg-tm_o)*w_d(Y,tg)));
dPdh=[dPdh(1)
dPdh(2)];
end
The ODE solver is called in the following manner:
tspan=linspace(0,height_dryer,100);
format long
[h,P]=ode45(#(h,P)gasstep1(h,P),tspan,[Y_o tg_o]);
The values from the generated arrays and P are used in a for loop to compute variables:
X1=zeros(1,Nh);Tm=zeros(1,Nh);
X1(1,1)=X_o;Tm(1,1)=tm_o;
for i=1:Nh-1
% Mass balance
X1(1,i+1)=X1(1,i)-dt*((P(i+1,1)-P(i,1))/(h(i+1)-h(i)))*(W_B/S)*(1/(rho_solid*(1-e)));
% Enthalpy balance
Tm(1,i+1)=Tm(1,i)+dt*(1/(c_s+c_al*X1(1,i)))*(q(((P(i+1,2)+P(i,2))/2),Tm(1,i))-...
((c_a-c_al)*(Tm(1,i))+hv(Tm(1,i)))*w_d((P(i+1,1)-P(i,1)), ((P(i+1,2)+P(i,2))/2)));
end
The doubt I have is whether the variables in the function w_d and q also change when I call the ODE solver in a loop. I found a method to implement the ODE solver in a loop on the mathworks website (link). I have found help provided when ODE parameters need to be changed (link).
I think my final code should look something like:
for j=2:Nt
for i=1:Nh-1
% compute X1 & Tm
end
% change variables in function w_d and q
% [call the ODE]
end
Could anyone please give me an idea on how to start the loop which would help me to complete the code.
The links you pointed to should answer your question: you could make w_d and q parameters of the gasstep function, and use the function parameterization as in the second link you posted.
From the code you posteed, I understand that you want w_d and q to be dependent on X1 and Tm, right? I'm going to assume that's the case. If they depend on other parameters, just use those instead of X1 and Tm in my explanation:
make gasstep1 dependent on X1 and Tm and pass them along to w_d and q: your gasstep1 function now has 4 arguments: gasstep1(h, P, X1, Tm), and w_d and q also (w_d(Y, tg, X1, Tm) for instance). Then you only need to create gasstep2 as such:
gasstep2 = #(h,P) gasstep1(h,P,X1,Tm)
and you can call ode45 on gasstep2!
Be careful that in your final code, if you write it like you presented above, X1 and Tm are going to depend on P, which needs to be initialized!