fsolve issue with initial condition for ODE - matlab

I am trying to solve the following ODE:
function [eta, sol] = compressible_similarity_wo
global Gamm Ma Pr omega;
Gamm = 1.4;
Ma = 2;
Pr = 0.7;
omega=0.76;
global eta_max_ode;
eta_max_ode = 20;
opt = optimset('Display','off','TolFun',1E-20);
F = fsolve(#(F) eval_boundary(F),[0,0,0.4,1,0],opt);
[eta_ode, fg_ode] = solve_ode(F);
sol = [fg_ode];
eta = eta_ode;
end
function [eta_ode, fg_ode] = solve_ode(F)
global eta_max_ode
options = odeset('RelTol',1e-9,'AbsTol',1e-9);
[eta_ode, fg_ode] = ode45(#BLFunc,[0,eta_max_ode],F,options);
end
function [g] = eval_boundary(F)
% Get the solution to the ODE with inital condition F
[eta_ode, fg_ode] = solve_ode(F);
% Get the function values (for BCs) at the starting/end points
f_start = fg_ode(1,1); %f(0) = 0
df_start = fg_ode(1,2); %f'(0) = 0
df_end = fg_ode(end,2); %f'(inf) - 1 = 0
t_end = fg_ode(end,4); %T(inf) - 1 = 0
dt_start = fg_ode(1,5); %T'(0) = 0
% Evaluate the boundary function
g = [f_start
df_start
df_end - 1
t_end - 1
dt_start];
end
function [df] = BLFunc(f)
global Gamm Ma Pr omega;
df = zeros(5,1);
df(1) = f(2);
df(2) = f(3);
df(3) = -f(1)*f(3)/(f(4)^(omega-1))-(omega-1)*f(3)/f(4);
df(4) = f(5);
df(5) = -Pr*f(1)*f(5)/(f(4)^(omega-1)) - Pr*(Gamm - 1.0)*Ma*Ma*f(3)*f(3) - (omega-1)*f(5)/f(4);
end
but fsolve returns the following problem
Error using BLFunc
Too many input arguments.
Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Error in solve_ode (line 5)
[eta_ode, fg_ode] = ode45(#BLFunc,[0,eta_max_ode],F,options);
Error in eval_boundary (line 3)
[eta_ode, fg_ode] = solve_ode(F);
Error in compressible_similarity_wo>#(F)eval_boundary(F) (line 15)
F = fsolve(#(F) eval_boundary(F),[0,0,0.4,1,0],opt);
Error in fsolve (line 230)
fuser = feval(funfcn{3},x,varargin{:});
Error in compressible_similarity_wo (line 15)
F = fsolve(#(F) eval_boundary(F),[0,0,0.4,1,0],opt);
Error in launch (line 3)
[eta, sol] = compressible_similarity_wo;
Caused by:
Failure in initial objective function evaluation. FSOLVE cannot continue.
Do you have an idea of what's going on?

I'll cite you the friendly manual page
The function dydt = odefun(t,y), for a scalar t and a column vector y, must return a column vector dydt of data type single or double that corresponds to f(t,y). odefun must accept both input arguments, t and y, even if one of the arguments is not used in the function.
That is, you simply need to change to
function [df] = BLFunc(t,f)
to get a result (no guarantee that it is THE result).

Try to replace BLFunc signature to
function [df] = BLFunc(t, f)
You need to provide odefun to ode45, which takes 2 arguments, as stated in documentation:
The function dydt = odefun(t,y), for a scalar t and a column vector y, must return a column vector dydt of data type single or double that corresponds to f(t,y). odefun must accept both input arguments, t and y, even if one of the arguments is not used in the function.

Related

Unable to meet integration tolerances in fmincon to solve ODE optimization problem

I have constrained ODE optimization problem to be solved using Matlab, I started by solving the ODE using ode15s which working will this initial values, also I had very good results without constraints using fminsearch, the problem started when I used fmincon it gave me these warnings:
Warning: Length of lower bounds is < length(x); filling in missing lower bounds with -Inf.
> In checkbounds (line 33)
In fmincon (line 318)
In Optimization (line 64)
Warning: Length of upper bounds is < length(x); filling in missing upper bounds with +Inf.
> In checkbounds (line 47)
In fmincon (line 318)
In Optimization (line 64)
Warning: Failure at t=2.340250e+01. Unable to meet integration tolerances without reducing the step size below the smallest value
allowed (5.684342e-14) at time t.
> In ode15s (line 668)
In ObjFun (line 6)
In barrier
In fmincon (line 813)
In Optimization (line 64)
I tried to remove constraints, but nothing changed...
y1_max = 5; y2_max = 2.3;
y01 = 1; y02 = 1.6;
%Control function parameter
Umin = -0.3; Umax = -0.1;
%Creation the structure of model parameters
params.T0=T0; params.Tf=Tf;
params.y1d=y1d; params.y2d=y2d;
params.y01=y01; params.y02=y02;
params.y2_max=y2_max;
n=2;
U0=-0.2*ones(1,n);
params.n=n;
params.U=U0; params.Umax=Umax; params.Umin=Umin;
params.dt=(Tf-T0)/n;
%for initial value of optimization parameters
options = odeset('RelTol',1e-7,'AbsTol',1e-7);
U=U0;
[t,y]=ode15s(#ODEsolver,[T0,Tf],[y01 y02],options,params);
%adding the ode solution as input prameters
params.t=t; params.y1= y(:,1); params.y2= y(:,2);
U0=-0.2*ones(1,n);
params.n=n; params.U=U0;
params.dt=(Tf-T0)/n;
A = [];
B = [];
Aq = []; Bq = [];
options1 = optimset('MaxIter',5000);
[x,fval,exitflag,output] = fmincon(#ObjFun,U0,A,B,Aq,Bq,Umin,Umax,IneqConst(U0,params),options1,params)
function y = ODEsolver(t,y,params)
dt = params.dt;
nu = floor(t/dt)+1;
nu = min(nu,params.n-1);
t1 = (nu-1)*dt;
Ut = params.U(nu) + ((t-t1)/dt)*(params.U(nu+1) - params.U(nu));
dy1a = ((0.63*y(1))/(1 + y(1)));
dy1b = (Ut*y(1)*y(2))/(1+0.6*y(1));
dy1 = dy1a + dy1b;
dy2a = (0.15*y(2))/(0.05-0.2*y(2));
dy2 = -0.2*y(2) + dy1b * dy2a;
y = [dy1; dy2];
end
function ObjFun1 = ObjFun(u,params)
% Calculating the value of the optimization criteria
params.U=u;
options = odeset('RelTol',1e-8,'AbsTol',1e-8);
[t,y]=ode15s(#ODEsolver,[0,100],[params.y01,
params.y02],options,params);
ObjFun1 =trapz(t,(y(:,1)-params.y1d).^2);
end
function [c,Const] = IneqConst(u, params)
params.U=u;
options = odeset('RelTol',1e-8,'AbsTol',1e-8);
[t,y]=ode15s(#ODEsolver,[0,100],[params.y01, params.y02],options,params);
c =[];
yCon = y(:,2)-params.y2_max;
Const = trapz(t,(abs(yCon)+yCon).^2);
end
The bug in this code is that the dimension of the bounds (Umin, Umax) should be an array with the same size of the control function U
so if the control function parameters n = 2 then Umin = [-0.3 -0.3] & Umax = [-0.1 -0.1]

How to address initial conditions for coupled system in Matlab

We have a coupled system of 10 ode each. The coupling presents in the last equation.
I thought about using a matrix 10 by 2 as initial conditions.I also followed a similar question with the same title here, but I still get the same errors ('Too many input arguments.')
time = [0 5];
x1_0 = [0 0 0 0 0 0 0 0 0 0];
x2_0 = [0 0 0 0 0 0 0 0 0 0];
initial = [x1_0;x2_0];
x = NaN(length(initial),2*length(time));
[t,x] = ode45(#ode,time,initial);
function [dxdt] = ode(x)
N = 2;
dxdt = NaN(10,2);
for i = 1:N
dxdt(1,i) = x(6,i);
dxdt(6,i) = (x(3,i)-x(4,i)+x(5,i)) - x(6,i) - x(1,i);
dxdt(2,i) = x(7,i);
dxdt(7,i) = (x(3,i)-x(4,i)+x(5,i)) - x(7,i) - x(2,i);
dxdt(3,i) = x(8,i);
dxdt(8,i) = (x(1,i)) - x(8,i) - x(3,i);
dxdt(4,i) = x(9,i);
dxdt(9,i) = (x(2,i)) - x(9,i) - x(4,i);
dxdt(5,i) = x(10,i);
if i == 1
j = 2;
elseif i == 2
j = 1 ;
end
dxdt(10,i) = (x(3,j)-x(4,j)+x(5,j)) - x(10,i) - x(5,i);
end
end
If my mistake is the use of a matrix initial conditions instead of a vector, using a 1 by 20 vector, and adjust the ode form accordingly would be not practical, I think
- What would be another more efficient way to address the initial conditions
-What is unnecessary from the inputs I have given and why?
-Is there any other computational way to represent the coupling?
EDIT: If I use the option: "function dxdt = ode(t,x)" the errors are the following:
Error in Test11>ode (line 33)
dxdt(10,i) = (x(3,j)-x(4,j)+x(5,j)) - x(10,i) - x(5,i);
Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options,
varargin);
Error in Test11 (line 9)
[t,x] = ode45(#ode,time,initial);
If I change the way I call the function, so that:
"[t,x] = ode45(#(t,x)ode(x), time, initial);"
the results are the following:
Not enough input arguments.
Error in Test11>ode (line 19)
dxdt(1,i) = x(6,i);
Error in Test11>#(t,x)ode(x)
Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options,
varargin);
Error in Test11 (line 9)
[t,x] = ode45(#(t,x)ode(x), time, initial);
The error 'Too many input arguments.' is caused by the fact that your ode function only accepts one variable, x, while ode45 is passing it two variables, time instance t and state x. Even if your ode equations are independent off the current time, you do need to handle this input argument.
Either let your ode function accept two input arguments:
function dxdt = ode(t,x)
% etc
or, change the way you call your ode function:
[t,x] = ode45(#(t,x)ode(x), time, initial);
Furthermore, I don't think ode45 can handle a 'state matrix', so I would indeed concatenate your two state vectors vertical to one large state vector. If your don't want to rewrite your code, add some reshapes before and after the loop:
function [dxdt] = ode(xv)
N = 2;
dxdt = NaN(10,2);
% reshape to two column vectors
x = reshape(xv,[],2); % xv is one large column vector
for ki = 1:N
dxdt(1,ki) = x(6,ki);
dxdt(6,ki) = (x(3,ki)-x(4,ki)+x(5,ki)) - x(6,ki) - x(1,ki);
dxdt(2,ki) = x(7,ki);
dxdt(7,ki) = (x(3,ki)-x(4,ki)+x(5,ki)) - x(7,ki) - x(2,ki);
dxdt(3,ki) = x(8,ki);
dxdt(8,ki) = (x(1,ki)) - x(8,ki) - x(3,ki);
dxdt(4,ki) = x(9,ki);
dxdt(9,ki) = (x(2,ki)) - x(9,ki) - x(4,ki);
dxdt(5,ki) = x(10,ki);
if ki == 1
kj = 2;
elseif ki == 2
kj = 1;
end
dxdt(10,ki) = (x(3,kj)-x(4,kj)+x(5,kj)) - x(10,ki) - x(5,ki);
end
% reshape dxdt to one column vector
dxdt = reshape(dxdt,[],1);
end

Matlab: fmincon throws error

I am implementing the expression given in the image which is the log-likelihood for AR(p) model.
In this case, p=2. I am using fmincon as the optimization tool. I checked the documentation and other examples over internet regarding the syntax of this command. Still, I am unable to mitigate the problem. Can somebody please help in eliminating the problem?
The following is the error
Warning: Options LargeScale = 'off' and Algorithm = 'trust-region-reflective' conflict.
Ignoring Algorithm and running active-set algorithm. To run trust-region-reflective, set
LargeScale = 'on'. To run active-set without this warning, use Algorithm = 'active-set'.
> In fmincon at 456
In MLE_AR2 at 20
Error using ll_AR2 (line 6)
Not enough input arguments.
Error in fmincon (line 601)
initVals.f = feval(funfcn{3},X,varargin{:});
Error in MLE_AR2 (line 20)
[theta_hat,likelihood] =
fmincon(#ll_AR2,theta0,[],[],[],[],low_theta,up_theta,[],opts);
Caused by:
Failure in initial user-supplied objective function evaluation. FMINCON cannot
continue.
The vector of unknown parameters,
theta_hat = [c, theta0, theta1, theta2] where c = intercept in the original model which is zero ; theta0 = phi1 = 0.195 ; theta1 = -0.95; theta2 = variance of the noise sigma2_epsilon.
The CODE:
clc
clear all
global ERS
var_eps = 1;
epsilon = sqrt(var_eps)*randn(5000,1); % Gaussian signal exciting the AR model
theta0 = ones(4,1); %Initial values of the parameters
low_theta = zeros(4,1); %Lower bound of the parameters
up_theta = 100*ones(4,1); %upper bound of the parameters
opts=optimset('DerivativeCheck','off','Display','off','TolX',1e-6,'TolFun',1e-6,...
'Diagnostics','off','MaxIter', 200, 'LargeScale','off');
ERS(1) = 0.0;
ERS(2) = 0.0;
for t= 3:5000
ERS(t)= 0.1950*ERS(t-1) -0.9500*ERS(t-2)+ epsilon(t); %AR(2) model y
end
[theta_hat,likelihood,exit1] = fmincon(#ll_AR2,theta0,[],[],[],[],low_theta,up_theta,[],opts);
exit(1,1)=exit1;
format long;disp(num2str([theta_hat],5))
function L = ll_AR2(theta,Y)
rho0 = theta(1); %c
rho1 = theta(2); %phi1
rho2 = theta(3); %phi2
sigma2_epsilon = theta(4);
T= size(Y,1);
p=2;
mu_p = rho0./(1-rho1-rho2); %mean of Y for the first p samples
%changed sign of the log likelihood expression
cov_p = xcov(Y);
L1 = (Y(3:end) - rho0 - rho1.*Y(1:end-1) - rho2.*Y(1:end-2)).^2;
L = (p/2).*(log(2*pi)) + (p/2).*log(sigma2_epsilon) - 0.5*log(det(inv(cov_p))) + 0.5*(sigma2_epsilon^-1).*(Y(p) - mu_p)'.*inv(cov_p).*(Y(p) - mu_p)+...
(T-p).*0.5*log(2*pi) + 0.5*(T-p).*log(sigma2_epsilon) + 0.5*(sigma2_epsilon^-1).*L1;
L = sum(L);
end
You are trying to pass constant parameters to the objective function (Y) in addition to the optimization variables (theta).
The right way of doing so is using anonymous function:
Y = ...; %// define your parameter here
fmincon( #(theta) ll_AR2(theta, Y), theta0, [],[],[],[],low_theta,up_theta,[],opts);
Now the objective function, as far as fmincon concerns, depends only on theta.
For more information you can read about anonymous functions and passing const parameters.

MATLAB strange error Gamma function numerical integration

i try to run the following in order to integrate numerically:
nu = 8;
psi=-0.2;
lambda = 1;
git = #(u) tpdf((0 - lambda * skewtdis_inverse(u, nu, psi)), nu);
g(t,i) = integral(git,1e-10,1-1e-10,'AbsTol',1e-16);
where tpdf is a matlab function and skewtdis:inverse looks like this:
function inv = skewtdis_inverse(u, nu, lambda)
% PURPOSE: returns the inverse cdf at u of Hansen's (1994) 'skewed t' distribution
c = gamma((nu+1)/2)/(sqrt(pi*(nu-2))*gamma(nu/2));
a = 4*lambda*c*((nu-2)/(nu-1));
b = sqrt(1 + 3*lambda^2 - a^2);
if (u<(1-lambda)/2);
inv = (1-lambda)/b*sqrt((nu-2)./nu)*tinv(u/(1-lambda),nu)-a/b;
elseif (u>=(1-lambda)/2);
inv = (1+lambda)/b*sqrt((nu-2)./nu).*tinv(0.5+1/(1+lambda)*(u-(1-lambda)/2),nu)-a/b;
end
What i get out is:
Error in skewtdis_inverse (line 6)
c = gamma((nu+1)/2)/(sqrt(pi*(nu-2))*gamma(nu/2));
Output argument "inv" (and maybe others) not assigned during call to "F:\Xyz\skewtdis_inverse.m>skewtdis_inverse".
Error in #(u)tpdf((0-lambda*skewtdis_inverse(u,nu,psi)),nu)
Error in integralCalc/iterateScalarValued (line 314)
fx = FUN(t);
Error in integralCalc/vadapt (line 133)
[q,errbnd] = iterateScalarValued(u,tinterval,pathlen);
Error in integralCalc (line 76)
[q,errbnd] = vadapt(#AtoBInvTransform,interval);
Error in integral (line 89)
Q = integralCalc(fun,a,b,opstruct);
If i , however call the function in thr handle directly there are no Problems:
tpdf((0 - lambda * skewtdis_inverse(1e-10, nu, psi)), nu)
ans =
1.4092e-11
tpdf((0 - lambda * skewtdis_inverse(1-1e-10, nu, psi)), nu)
ans =
7.0108e-10
Your effort is highly appreciated!
By default, integral expects the function handle to take a vector input.
In your code, the if-statement creates a complication since the condition will evaluate to true only if all elements of u satisfy it.
So, if u is a vector that has elements both greater than and less than (1-lambda)/2, inv will never be assigned.
There are two options:
Put the if-statement in a for-loop and iterate over all of the elements of u.
Use logical indexes for the assignment.
The second option is faster for large element count and, in my opinion, cleaner:
inv = u; % Allocation
IsBelow = u < (1-lambda)/2; % Below the threshold
IsAbove = ~IsBelow ; % Above the threshold
inv(IsBelow) = (1-lambda)/b*sqrt((nu-2)./nu)*tinv(u(IsBelow)/(1-lambda),nu)-a/b;
inv(IsAbove) = (1+lambda)/b*sqrt((nu-2)./nu)*tinv(0.5+1/(1+lambda)*(u(IsAbove)-(1-lambda)/2),nu)-a/b;

Create flexible function handle

I am using numerical integration in MATLAB, with one varibale to integrate over but the function also contains a variable number of terms depending on the dimension of my data. Right now this looks like the following for the 2-dimensional case:
for t = 1:T
fxt = #(u) exp(-0.5*(x(t,1)-theta*norminv(u,0,1)).^2) .* ...
exp(-0.5*(x(t,2) -theta*norminv(u,0,1)).^2);
f(t) = integral(fxt,1e-4,1-1e-4,'AbsTol',1e-3);
end
I would like to have this function flexible in the sense that there could be any number of data points in, each in the following term:
exp(-0.5*(x(t,i) -theta*norminv(u,0,1)).^2);
I hope this is understandable.
If x and u have a valid dimension match (vector-vector or array-scalar) for the subtraction, you can put the whole matrix x into the handle and pass it to the integral function using the name-parameter pair ('ArrayValued',true):
fxt = #(u) exp(-0.5*(x - theta*norminv(u,0,1)).^2) .* ...
exp(-0.5*(x - theta*norminv(u,0,1)).^2);
f = integral(fxt,1e-4,1-1e-4,'AbsTol',1e-3,'ArrayValued',true);
[Documentation]
You may need a loop if integral ever passes a vector u into the handle.
But in looking at how the integral function is written, the integration nodes are entered as scalars for array-valued functions, so the loop shouldn't be necessary unless some weird dimension-mismatch error is thrown.
Array-Valued Output
In response to the comments below, you could try this function handle:
fx = #(u,t,k) prod(exp(-0.5*(x(t,1:k)-theta*norminv(u,0,1)).^2),2);
Then your current loop would look like
fx = #(u,t,k) prod(exp(-0.5*(x(t,1:k)-theta*norminv(u,0,1)).^2),2);
k = 2;
for t = 1:T
f(t) = integral(#(u)fx(u,t,k),1e-4,1-1e-4,'AbsTol',1e-3,'ArrayValued',true);
end
The ArrayValued flag is needed since x and u will have a dimension mismatch.
In this form, another loop would be needed to sweep through the k indexes.
However, we can improve this function by skipping the loop altogether since each iterate of the loop is independent by using the ArrayValued mode:
fx = #(u,k) prod(exp(-0.5*(x(:,1:k)-theta*norminv(u,0,1)).^2),2);
k = 2;
f = integral(#(u)fx(u,k),1e-4,1-1e-4,'AbsTol',1e-3,'ArrayValued',true);
Vector-Valued Output
If ArrayValued is not desired, which may be the case if the integration requires a lot of subdivisions and a vector-valued u is preferable, you can also try a recursive version of the handle using cell arrays:
% x has size [T,K]
fx = cell(K,1);
fx{1} = #(u,t) exp(-0.5*(x(t,1) - theta*norminv(u,0,1)).^2);
for k = 2:K
fx{k} = #(u,t) fx{k-1}(u,t).*exp(-0.5*(x(t,k) - theta*norminv(u,0,1)).^2);
end
f(T) = 0;
k = 2;
for t = 1:T
f(t) = integral(#(u)fx{k}(u,t),1e-4,1-1e-4,'AbsTol',1e-3);
end
ThanksTroy but now I run into the follwing:
x = [0.3,0.8;1.5,-0.7];
T = size(x,1);
k = size(x,2);
theta= 1;
fx = #(u,t,k) prod(exp(-0.5*(x(t,1:k) - theta*norminv(u,0,1))^2));
for t = 1,T
f(t) = integral(#(u)fx(u,t,k),1e-4,1-1e-4,'AbsTol',1e-3);
end
Error using -
Matrix dimensions must agree.
Error in #(u,t,k)prod(exp(-0.5*(x(t,1:k)-theta*norminv(u,0,1))^2))
Error in #(u)fx(u,t,k)
Error in integralCalc/iterateScalarValued (line 314)
fx = FUN(t);
Error in integralCalc/vadapt (line 133)
[q,errbnd] = iterateScalarValued(u,tinterval,pathlen);
Error in integralCalc (line 76)
[q,errbnd] = vadapt(#AtoBInvTransform,interval);
Error in integral (line 89)
Q = integralCalc(fun,a,b,opstruct);