Use Fzero in BC function of pdepe with Matlab - matlab

I have to solve some parabolic PDE system with pdepe in Matlab.
is't possible and secure to call Fzero function inside boundary conditions function in Pdepe solver like this?
function [pl,ql,pr,qr] = pdex5bc(~,ul,~,ur,~)
kappa = nref*Dref*q/L;
jcell0 = 0;
k0 = 0.1;
options = optimset('Display','iter'); % show iterations
jcell = fzero(#curOc,k0,options); % Call solver
pl = [jcell0 ; -1/(2*epsilonp)*jcell0/kappa ; 3/(2*epsilonp)*jcell0/kappa ;...
jcell ; -1/(2*epsilonp)*jcell/kappa ; 3/(2*epsilonp)*jcell/kappa];
ql = [kappa ; 1 ; 1 ; kappa ; 1 ; 1];
pr = [0 ; -1/(2*epsilonp)*jcell0/kappa ; 3/(2*epsilonp)*jcell0/kappa ;...
0 ; -1/(2*epsilonp)*jcell/kappa ; 3/(2*epsilonp)*jcell/kappa];
qr = [1 ; 1 ; 1 ; 1 ; 1 ; 1];
function F = curOc(z)
deltaVint = (Rtco+Rext)*(Rp/(Rext+Rtco+Rp))*A*z*J0;
Eta = Pot+Vt/2*log(ur(2)/ur(3)^3)+Vt*log(ul(4)/Ncb)- deltaVint ;
F = z - (ur(5)/ur(2)*exp(beta*Eta/Vt)- ur(6)/ur(3)*exp(-(1-beta)*Eta/Vt));
end
end
Let me expose my problem : When I execute this code, following error occurs:
*Error using fzero (line 289)
FZERO cannot continue because user supplied function_handle ==>
pdeDSSC_new8bis/pdex5bc/curOc
failed with the error below.
User function 'pdeDSSC_new8bis/pdex5bc/curOc' returned a complex value
when evaluated at 20;*
FZERO cannot continue.
At some time integration of pdepe,fsolve returns a complex root. This happens when ul and ur become negatives.
Does someone can explain to me the problem?

Related

Boundary value problem in MATLAB, issue with fsolve

I am trying to solve and ODE with boundary conditions at 0 and end, ws.mat can be downloaded at https://gofile.io/?c=RYzPsO
clear all
clc
global omega eta_max_ode eta F T Tp
eta_max_ode = 10;
omega=0.76;
load('ws','T','Tp','F','eta')
IC=[0,1];
opt = optimset('Display','off','TolFun',1E-20);
FI = fsolve(#(FI) eval_boundary_UVWTI(FI),IC,opt)
[eta_ode_i, fg_ode_i] = solve_UVWTI(FI);
sol_i = [fg_ode_i];
eta_i = eta_ode_i;
plot(eta_i,sol_i(:,1))
function [dfi]=UVWTI(t,fi)
global omega eta_max_ode eta F T Tp
for i=1:length(eta)
if eta(i)<t
else
inde=i;
break
end
end
A11=0;
A12=1;
A21=0;
A22=-(T(inde)^(1-omega))*F(inde)-omega*Tp(inde)/T(inde)+Tp(inde)/T(inde);
dfi=zeros(2,1);
dfi(1)=A11*fi(1)+A12*fi(2);
dfi(2)=A21*fi(1)+A22*fi(2);
end
function [eta_ode_i, fg_ode_i] = solve_UVWTI(FI)
global eta_max_ode eta
options = odeset('RelTol',1e-9,'AbsTol',1e-9);
[eta_ode_i, fg_ode_i] = ode45(#UVWTI,eta,FI,options);
size(fg_ode_i);
end
function [gi] = eval_boundary_UVWTI(FI)
% Get the solution to the ODE with inital condition F
[eta_ode_i, fg_ode_i] = solve_UVWTI(FI);
% Get the function values (for BCs) at the starting/end points
w_start = fg_ode_i(1,1); %w(0) = 0
w_end = fg_ode_i(end,1); %w(inf) = 0
% Evaluate the boundary function
gi = [
w_start
w_end - 1
];
end
I obtained the correct behaviour this is the solution tending to a constant. However, I should get sol_i(:,1) tending to 1 and fsolve does not seem to calculate the correct initial condition so that this happen. What's wrong in the code? eval_boundary_UVWTI() seems to be correct

Integrating over a constant function

I am trying to integrate over a constant function in MATLAB 2017a, but I am stuck. First of all when I integrate using the following script, I get the right output. So the script works for a x0 which depends on t.
function E=sol(n,k)
x0 = #(t) t^(2);
j = 0;
E = zeros(n,1);
while j < n+1 ;
K = matlabFunction(subs(po(j,k))) ;
eval(sprintf('x%d = integral(K,0,1);',j+1)) ;
E(j+1,1) = subs(sprintf('x%d',j+1))
j = j+1;
end
end
Where function po(j,k) is as follows,
function A_j = po(j,k) % Adomian polynomials
if j >0
x = sym('x',[1 j]);
syms p; % Assinging a symbolic variable for p
syms x0;
S = x0+ sum(p.^(1:j) .* x) ; % Sum of p*x up to order j
Q =f(S,k); % Taking the k-th power of S, i.e.
A_nc = diff(Q,p,j)/factorial(j); % Taking the j-th order derivative
A_j = subs(A_nc,p,0) ; % Filling in p=0
else
syms x0;
S = x0;
A_j =f(S,k); % Taking the k-th power of S,
end
end
And where f(x,k) is,
function F = f(x,k) % Nonlinear function of k power
F = x^k ;
end
Now when I cal sol(n,k) it does work. But when I try to change my x0 function in sol(n,k) in a constant function like,
function E=solcon(n,k)
x0 = #(t) 2.*ones(size(t));
j = 0;
E = zeros(n,1);
while j < n+1 ;
K = matlabFunction(subs(po(j,k))) ;
eval(sprintf('x%d = integral(K,0,1);',j+1)) ;
E(j+1,1) = subs(sprintf('x%d',j+1))
j = j+1;
end
end
It does not work, As you can see I added *ones(size(t)); just to make it a function of t. But unfortunately it still doesn't work when I call,
K = matlabFunction(subs(po(j,k))) ;
I get,
#()4.0
And then I get an error when I call,
eval(sprintf('x%d = integral(K,0,1);',j+1))
Could anyone help me out trying to integrate over a constant?
The error I get when I call solcon(10,2) is
Error using symengine>#()4.0
Too many input arguments.
Error in integralCalc/iterateScalarValued (line 314)
fx = FUN(t);
Error in integralCalc/vadapt (line 132)
[q,errbnd] = iterateScalarValued(u,tinterval,pathlen);
Error in integralCalc (line 75)
[q,errbnd] = vadapt(#AtoBInvTransform,interval);
Error in integral (line 88)
Q = integralCalc(fun,a,b,opstruct);
Error in solcon1 (line 7)
eval(sprintf('x%d = integral(K,0,1);',j+1)) ;
EDIT 2
I used the following script,
function E=solcon(n,k)
x0 = #(t) 2.*ones(size(t));
j = 0;
E = zeros(n,1);
while j < n+1 ;
K = matlabFunction(subs(po(j,k))) ;
fstr= func2str(K)
if fstr(3) == ')';
x{j+1} = K*(1-0)
else x{j+1} = integral(K,0,1)
end
E(j+1,1) = subs(x{j+1},1);
j = j+1
end
end
But the following error occurs,
Undefined operator '*' for input arguments of type 'function_handle'.
Error in solcone1 (line 9)
x{j+1} = K*(1-0);
I am going to ignore the terrible choice of using eval, especially when you can do
x{j+1} = integral(K,0,1);
Read more on why dynamic variables and eval are terrible
Your problem is that matlabFunction is a smartass. When it detects that your function does not have any dependency to x, it gives you a function with empty input arguments #()4.0. As you see, integral does not like that.
A way of solving the problem is detecting this before calling integral. You could check if it has input arguments, and if it does not, then evaluate the integral "by hand"
...
while j < n+1 ;
K = matlabFunction(subs(po(j,k))) ;
fstr=func2str(K);
if fstr(3)==')'
x{j+1}=K()*(1-0); % evaluate the integral yourself
else
x{j+1} = integral(K,0,1);
end
E(j+1,1) = subs(x{j+1});
j = j+1;
end
...
The problem is considerably more difficult that I though I was. Either rewrite the entire thing, or using eval:
...
while j < n+1 ;
K = matlabFunction(subs(po(j,k))) ;
fstr=func2str(K);
if j==0
eval(sprintf('x%d = K()*(1-0);;',j+1)) ;
else
eval(sprintf('x%d = integral(K,0,1);',j+1)) ;
end
E(j+1,1) = subs(sprintf('x%d',j+1));
j = j+1;
end
...

Solving nonlinear system of differential equations in matlab usin ODE45

i am trying to solve a system of nonlinear differential equation using ODE45 MATLAB , i did that many times successfully , but this time i get the following error and i really don't know what is wrong i am confused compeletly. here are the codes.
%% this is the error:
Subscript indices must either be real positive integers or logicals.
Error in non_L_ss (line 6)
(-Fk*(ds0+x(3)-x(1))+Fk*ds0-Fc(x(4)-x(2)))/ms +Fa/ms ] ;
Error in odearguments (line 87)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed,solver_name,ode, tspan,y0,optio varargin);
Error in solve (line 50)
[t X]=ode45(#non_L_ss,t_span,IC);
%% the equations be defined in a function:
function dX=non_L_ss(t,x)
global Fk Fc kt Fa q ds0 ms mu
dX=[ x(2);
(Fk*(ds0+x(3)-x(1))-Fk*ds0+Fc*(x(4)-x(2))-kt*x(1))/mu-Fa/m-kt*q/mu ;
x(4);
(-Fk*(ds0+x(3)-x(1))+Fk*ds0-Fc(x(4)-x(2)))/ms +Fa/ms ] ;
end
%% and here the function be called to solve by ODE45:
clear
clc
global Fk Fc kt Fa q ds0 ms mu qdot v2
mu = 100 ;
ms = 1242 ;
k1s = 80000 ;
k2s = 32000 ;
kt = 405000 ;
c1s = 4000 ;
c2s = 1600 ;
v = 20 ;
Gq = 256e-6 ;
ds0 = 0.1538 ;
a = 1 ;
b = 0.001 ;
n0 = 0.1 ;
f0 = 0.011*v ;
w = 0.5 ;
Fa = 2000 ;
q = 0.05 ;
xs = 0.1 ;
xu = 0.1 ;
dxs = 0.1 ;
dxu = 0.2 ;
Fk = k1s+k2s*(ds0+xs-xu).^2 ;
if dxs >= dxu
Fc = c1s ;
elseif dxs < dxu
Fc = c2s ;
end
t_span=[0 1];
IC=[2 3 2 2];
[t X]=ode45(#non_L_ss,t_span,IC);
Subscript indices must either be real positive integers or logicals.
Error in non_L_ss (line 6)
(-Fk*(ds0+x(3)-x(1))+Fk*ds0-Fc(x(4)-x(2)))/ms +Fa/ms ] ;
means that you use something as an indexed array with a non-integer index. Which probably means that the object is no array at all. I'd propose to replace
Fc(x(4)-x(2))
by
Fc*(x(4)-x(2))
to try to solve this issue.

Methods for Linear system solution with matlab

I have a linear system Ax = b , which is created by natural splines and looks like this:
where
The code in matlab which is supposed to solve the system is the following:
clear;
clc;
x = [...] ;
a = [...];
x0 = ...;
n = length(x) - 1 ;
for i = 0 : (n-1)
h(i+1) = x(i+2) - x(i+1) ;
end
b= zeros( n+1 , 1 ) ;
for i =2: n
b(i,1) = 3 *(a(i+1)-a(i))/h(i) - 3/h(i-1)*(a(i) - a(i-1) ) ;
end
%linear system solution.
l(1) =0 ; m(1) = 0 ; z(1) = 0 ;
for i =1:(n-1)
l(i+1) = 2*( x(i+2) - x(i) ) - h(i)* m(i) ;
m(i+1) = h(i+1)/l(i+1);
z(i+1) = ( b(i+1) - h(i)*z(i) ) / l ( i+1) ;
end
l(n+1) =1;
z(n+1) = 0 ;
c(n+1) = 0 ;
for j = ( n-1) : (-1) : 0
c(j+1) = z(j+1) - m(j+1)*c(j+2) ;
end
but I can't understand which method is being used for solving the linear system.
If I had to guess I would say that the LU method is used, adjusted for tridiagonal matrices, but I still can't find the connection with the code...
Any help would be appreciated!!!
The coefficients look a little odd (particularly that 2 in the l equation), but it looks like a specialized Thomas Algorithm where:
The second-to-last loop performs a forward elimination of the subdiagonal to bring the matrix into upper triangular form.
The last loop performs the back substitution for the solution.
The code doesn't seem to match one-to-one with the general algorithm since the solution is using the vectors that compose the diagonals instead of the diagonals themselves with no apparent preallocation of memory. So I can't say if this method is "better" than the general one off the bat.

Odes15 sub plotting, differential equations

So I have three differential equations relating to diabetes, I have to plot the 2 out of the three, them being G and I in a subplot. For some reason when I attempt to run it the command window prints out: "Not enough input arguments" This is the criteria for it:
function dx = problem1(t,x)
P1 = 0.028735 ;
P2 = 0.028344 ;
P3 = 5.035 * 10^(-5) ;
Vi = 12 ;
n = 5/54 ;
D_t = 3*exp(-0.05*t) ;
U_t = 3 ;
Gb = 4.5;
Xb = 15;
Ib = 15;
G = x(1);
X = x(2);
I = x(3);
dx = zeros(3,1);
dx(1) = -P1*(G-Gb) - (X-Xb)*G + D_t ;
dx(2) = -P2*(X-Xb) + P3*(I-Ib) ;
dx(3) = -n*I + U_t/Vi ;
[T,X] = ode15s(#problem1,[0 60*24],[4.5 15 15]) ;
subplot(3,1,1);
plot(T,X(:,1)); % Plot G
subplot(3,1,2); % Second subplot
plot(T,X(:,2)); % Plot I
The error is thrown when you run the function and MATLAB attempts to evaluate D_t = 3*exp(-0.05*t);. Since no value of t was given, MATLAB throws an error saying that the up-to-that-point unused t variable must be specified.
The main problem with the code is in the function's design. Namely, ode15s needs a function that accepts a t and an x and returns dx; however, as it is currently laid out, the call to ode15s is embedded within problem1 which itself requires a t and x. It is a chicken-or-egg problem.
All of the input is correct aside from this design problem and can easily be corrected using a separate function for the ODE's definition:
function problem1
[T,X] = ode15s(#ODE,[0 60*24],[4.5 15 15]) ;
subplot(3,1,1);
plot(T,X(:,1)); % Plot G
subplot(3,1,2); % Second subplot
plot(T,X(:,2)); % Plot I
end
function dx = ODE(t,x)
P1 = 0.028735 ;
P2 = 0.028344 ;
P3 = 5.035 * 10^(-5) ;
Vi = 12 ;
n = 5/54 ;
D_t = 3*exp(-0.05*t) ;
U_t = 3 ;
Gb = 4.5;
Xb = 15;
Ib = 15;
G = x(1);
X = x(2);
I = x(3);
dx = zeros(3,1);
dx(1) = -P1*(G-Gb) - (X-Xb)*G + D_t ;
dx(2) = -P2*(X-Xb) + P3*(I-Ib) ;
dx(3) = -n*I + U_t/Vi ;
end
Notes:
The first line function problem1 is short-hand for function [] = problem1(). I prefer the latter form myself, but I'm in the minority.
The function handle passed to ode15s #ODE is short-hand for #(t,x) ODE(t,x). I prefer the latter form myself, but it is no less or more valid as long as you are not parametrizing functions.
You can also use a nested function and give the problem1 function access to the model constants, but I opted for a separate function here.