Matlab PDE Solver Issue - matlab

Im trying to solve the transient heat equation in 1D and comparing the analytical and numerial solutions. The solutions have the same trend but are very different, also the relative error is coming out to be zero, even though its clearly not supposed to be. Im not sure if I have solved the PDE correctly. (the pde is du/dt = d^2u/dx^2) and bcs are u(0,t)=1, u(100,t) = 0, u(x,0)=0. Can someone please take a look at my code?
function he
m = 0;
x = linspace(0,100,500);
t = linspace(0,1000,500);
sol = pdepe(m,#hepde,#heic,#hebc,x,t);
u = sol(:,:,1);
y = erfc(x./(2*(t.^0.5)));
r=(y-u(70,:))/y;
figure;
plot(x,u(50,:),'.',x,u(150,:),'.',x,u(250,:),'.',x,u(end,:),'.',x,y,'.');
title('Numerical Solutions at different times.');
legend('t=100','t=300','t=500','t=700','y ana',0);
xlabel('Distance x');
ylabel('u(x,t)');
figure;
plot(x,r);
title('error in numerical and analytical solution');
legend('error',0);
xlabel('Distance x');
ylabel('error');
% --------------------------------------------------------------------------
function [c,f,s] = hepde(x,t,u,DuDx)
c = 1;
f = DuDx;
s = 0;
% --------------------------------------------------------------------------
function u0 = heic(x)
u0 = 0;
% --------------------------------------------------------------------------
function [pl,ql,pr,qr] = hebc(xl,ul,xr,ur,t)
pl = ul-1;
ql = 0;
pr = ur;
qr = 0;

You actually had the solution all set up correctly, you just used the results incorrectly. I'll go through the errors one by one.
sol = pdepe(m,#hepde,#heic,#hebc,x,t);
u = sol(:,:,1);
You found the right answer, but the line u=sol(:,:,1); is useless as size(sol)=[2 2], so you may as well just do u=pdepe(...);.
Now when you calculated your exact solution you did it very strangely. You want to find it at each x/t combination, but you did it only at some of them. You need to use meshgrid to get all the combinations of x and t then calculate your exact solution at each one.
[X,T]=meshgrid(x,t);
y = erfc(X./(2*(T.^0.5)));
Then you need to calculate the error differently.
r=(y-u)./y;
figure(3);
And plot differently.
plot(x,u(50,:),'b',x,u(150,:),'g',x,u(250,:),'r',x,u(end,:),'c',x,y(50,:),'b--',x,y(150,:),'g--',x,y(250,:),'r--',x,y(end,:),'c--');
Actually your exact solution doesn't satisfy the boundary condition at x=100......

Related

How to solve a second order non linear ode system with bvp4c?

I'm trying to solve a system of two second order non linear Odes and since it is a boundary valued problem I suppose I need to use the bvp4c function.
The system I'm talking about is the following:
f''(x) = F(f,f',x);
s''(x) = G(f, f',s,s',x)
with the conditions f(0) = pi, f(inf = 35) = s(inf = 35) = 0. The F and G functions are known and I assumed that 35 would be a decent replacement for infinity.
It is separable and I have already solved for f but I don't know how to solve it for s either.
The code that allegedly solves for f is the following:
options = bvpset('RelTol', 1e-5);
Xstart = 0.01;
Xend = 35;
solinit = bvpinit(linspace(Xstart, Xend, 1000), [0, 1]);
sol = bvp4c(#twoode, #twobc, solinit, options);
x = linspace(Xstart,Xend);
y = deval(sol,x);
figure(1)
plot(x,y(1,:))
figure(2)
plot(x,y(2,:))
function dydx = twoode(x,y)
dydx = [y(2); ((-1/(x^2 + 2+sin(y(1))^2))*(2*x*y(2) + sin(2*y(1))*y(2)^2 -
2*sin(2*y(1)) - (sin(y(1)^2)*sin(2*y(1)))/x^2) )];
end
function res = twobc(ya,yb)
res = [ya(1) - pi
yb(2)];
end
So my question is how can I use the results I obtained for f in order to solve the equation for s? I have tried doing the same things I did for f but if I define a function for s that uses y(1,:) and y(2,:) it gives me an error message that says y is not defined.
Since I am quite new to solving dfferential equations with Matlab and to using Matlab in general I am probably making some trivial mistake but I have been looking for answers and couldn't find any. I hope someone with enough patience can help me.
Thanks in advance for any useful advice.

How to implement an guess correcting algorithm when solving a BVP with shooting method?

I have a boundary value problem (specified in the picture below) that is supposed to be solved with shooting method. Note that I am working with MATLAB when doing this question. I'm pretty sure that I have rewritten the differential equation from a 2nd order differential equation to a system of 1st order differential equations and also approximated the missed value for the derivative of this differential equation when x=0 using the secant method correctly, but you could verify this so you'll be sure.
I have done solving this BVP with shooting method and my codes currently for this problem is as follows:
clear, clf;
global I;
I = 0.1; %Strength of the electricity on the wire
L = 0.400; %The length of the wire
xStart = 0; %Start point
xSlut = L/2; %End point
yStart = 10; %Function value when x=0
err = 5e-10; %Error tolerance in calculations
g1 = 128; %First guess on y'(x) when x=0
g2 = 89; %Second guess on y'(x) when x=0
state = 0;
X = [];
Y = [];
[X,Y] = ode45(#calcWithSec,[xStart xSlut],[yStart g1]');
F1 = Y(end,2);
iter = 0;
h = 1;
currentY = Y;
while abs(h)>err && iter<100
[X,Y] = ode45(#calcWithSec,[xStart xSlut],[yStart g2]');
currentY = Y;
F2 = Y(end,2);
Fp = (g2-g1)/(F2-F1);
h = -F2*Fp;
g1 = g2;
g2 = g2 + h;
F1 = F2;
iter = iter + 1;
end
if iter == 100
disp('No convergence')
else
plot(X,Y(:,1))
end
calcWithSec:
function fp = calcWithSec(x,y)
alpha = 0.01; %Constant
beta = 10^13; %Constant
global I;
fp = [y(2) alpha*(y(1)^4)-beta*(I^2)*10^(-8)*(1+y(1)/32.5)]';
end
My problem with this program is that for different given I's in the differential equation, I get strange curves that does not make any sense in physical meaning. For instance, the only "good" graph I get is when I=0.1. The graph to such differential equations is as follows:
But when I set I=0.2, then I get a graph that looks like this:
Again, in physical meaning and according to the given assignment, this should not happen since it gets hotter you closer you get to the middle of the mentioned wire. I want be able to calculate all I between 0.1 and 20, where I is the strength of the electricity.
I have a theory that it has something to do with my guessing values and therefore, my question is about if there is possible to implement an algorithm that forces the program to adjust the guessing values so I can get a graph that is "correct" in physical meaning? Or is it impossible to achieve this? If so, then explain why.
I have struggled with this assignment many days in row now, so all help I can get with this assignment is worth gold to me now.
Thank you all in advance for helping me out of this!

Matlab: 1D Numerical PDEs without Loops

So, currently I am trying to find the numerical solutions for the berger equation, $u_t+u∗u_x=0$. The numerical solution to this equation is:
$u^{n+1}_j=u_n^j−\frac{Δx}{Δt}u^n_j(u^n_j−u^n_{j−1})$
I wrote code on Matlab that computes this. As you can see, there is only one for-loop in the code. However, my u matrix extremely large, the algorithm becomes slow. Is there a way for me to use no loops at all. I was thinking about using the command cumsum, but I am not sure how to integrate that to my program. Please look at my code. Thanks.
dx = 0.9;
dt = 0.9;
tf = 10;
l = 10;
xstep = [-1:dx:l];
tstep = [0:dt:tf];
uinit = zeros(length(tstep),length(xstep));
%%Setting Initial and Boundary Conditions
bc.left = #(t) 2;
bc.right = #(t) -1;
ic = #(x) ...
2*(x<=0) ...
-1*(x>0);
uinit(1, :) = ic(xstep);
uinit(:, 1) = bc.left(tstep);
uinit(:, end) = bc.right(tstep);
%% Numerical method part
for c=1:(length(tstep)-1)
uinit(2:end -1, c+1) = uinit(2:end -1, c) - dx/dt*(uinit(2:end -1, c).*(uinit(2:end-1, c) - uinit(1:end-2, c)));
end
surf(xstep,tstep,uinit)

Is this correct approach for a single summation in time domain in Matlab?

I am trying to do a single summation of a function in the time domain. I got my code working, but I would feel more confident if someone would verify the correctness or point out my mistakes.
Here is a picture of the formula I am trying to code:
And here is the code itself:
h = 100;
t=[1:400];
rho_w = 1025;
g = 9.81;
Ohm = [0.01:0.01:4]
Phase = rand(1,length(Ohm))*2*pi;
Amp = [1:1:400];
for i = 1:length(t)
P(i) = rho_w*g*sum(Amp.*Ohm.*cos(Ohm*t(i)+Phase))
end
I think it's correct (thanks to #horchler for his valuable comment).
You can also do it with bsxfun:
P = rho_w*g*sum( bsxfun(#times, (Amp.*Ohm).', ...
cos(bsxfun(#plus, bsxfun(#times, Ohm.', t), Phase.'))) );

Need help plotting this function in Matlab

I recently started using Matlab and I am trying to plot Imaginary part of a function. I can see I am making a mistake somewhere because I have the graph showing what I need to get and I am getting something else. Here is the link of the graph that I need to get, that I am getting and a function that I am plotting:
I know that this function has a singularity at frequency around 270 Hz and I don't know if a 'quadgk' can solve integral then. You guys probably know but theta function inside the integral is a heaviside and I don't know if that is causing problem maybe? Is there something wrong I am doing here? Here is the matlab code I wrote:
clear all
clc
ff=1:10:1000;
K1=(2*3)*log(2*cosh(135/6))/pi;
theta1=ones(size(ff));
theta1(ff<270)=0;
I1=zeros(size(ff));
for n = 1:numel(ff)
f = ff(n);
I1(n)= K1/f + (f/pi)*quadgk(#(x)(sinh(x/3)/(cosh(135/3)+cosh(x/3))-theta1(n))./((f^2)-4*(x.^2)), 0, inf);
end
plot(ff,I1, 'b');
hold on
axis([0 1000 -0.3 1])
First, I altered the expression for your heaviside function to what I think is the correct form.
Second, I introduced the definitions of mu and T explicitly.
Third, I broke down the integral into 4 components, as follows, and evaluated them individually (along the lines of what Fraukje proposed)
Fourth, I use quadl, although this is prob. of minor importance.
(edit) Changed the range of ff
Here's the code with changes:
fstep=1;
ff=[1:fstep:265 275:fstep:1000];
T = 3;
mu = 135;
df = 0.01;
xmax = 10;
K1=(2*T/pi)*log(2*cosh(mu/(2*T)));
theta1=ones(size(ff));
theta1(ff-2*mu<0)=0;
I1=zeros(size(ff));
for n = 1:numel(ff)
f = ff(n);
sigm1 = #(x) sinh(x/T)./((f^2-4*x.^2).*(cosh(mu/T)+cosh(x/T)));
sigm2 = #(x) -theta1(n)./(f^2-4*x.^2);
I1(n) = K1/f + (f/pi)*quadl(sigm1,0,f/2-df); % term #1
% I1(n) = I1(n) + (f/pi)*quadl(sigm1,f/2+df,xmax); % term #2
% I1(n) = I1(n) + (f/pi)*quadl(sigm2,0,f/2-df); % term #3
% I1(n) = I1(n) + (f/pi)*quadl(sigm2,f/2+df,xmax); % term #4
end
I selected to split the integrals around x=f/2 since there is clearly a singularity there (division by 0). But additional problems occur for terms #2 and #4, that is when the integrals are evaluated for x>f/2, presumably due to all of the trigonometric terms.
If you keep only terms 1 and 3 you get something reasonably similar to the plot you show:
However you should probably inspect your function more closely and see what can be done to evaluate the integrals for x>f/2.
EDIT
I inspected the code again and redefined the auxiliary integrals:
I1=zeros(size(ff));
I2=zeros(size(ff));
I3=zeros(size(ff));
for n = 1:numel(ff)
f = ff(n);
sigm3 = #(x) sinh(x/T)./((f^2-4*x.^2).*(cosh(mu/T)+cosh(x/T))) -theta1(n)./(f^2-4*x.^2);
I1(n) = K1/f + (f/pi)*quadl(sigm3,0,f/2-df);
I2(n) = (f/pi)*quadl(sigm3,f/2+df,10);
end
I3=I2;
I3(isnan(I3)) = 0;
I3 = I3 + I1;
This is how the output looks like now:
The green line is the integral of the function over 0<x<f/2 and seems ok. The red line is the integral over Inf>x>f/2 and clearly fails around f=270. The blue curve is the sum (the total integral) excluding the NaN contribution when integrating over Inf>x>f/2.
My conclusion is that there might be something wrong with the curve as you expect it to look.
So far I'd proceed this way:
clc,clear
T = 3;
mu = 135;
f = 1E-04:.1:1000;
theta = ones(size(f));
theta(f < 270)= 0;
integrative = zeros(size(f));
for ii = 1:numel(f)
ff = #(x) int_y(x, f(ii), theta(ii));
integrative(ii) = quad(ff,0,2000);
end
Imm = ((2*T)./(pi*f)).*log(2*cosh(mu/(2*T))) + (f/pi).*integrative;
Imm1 = exp(interp1(log(f(1:2399)),log(Imm(1:2399)),log(f(2400):.001:f(2700)),'linear','extrap'));
Imm2 = exp(interp1(log(f(2985:end)),log(Imm(2985:end)),log(f(2701):.001:f(2984)),'linear','extrap'));
plot([(f(2400):.001:f(2700)) (f(2701):.001:f(2984))],[Imm1 Imm2])
hold on
axis([0 1000 -1.0 1])
plot(f,Imm,'g')
grid on
hold off
with
function rrr = int_y(x,f,theta)
T = 3;
mu = 135;
rrr = ( (sinh(x./T)./(cosh(mu/T) + cosh(x/T))) - theta ) ./ (f.^2 - 4.*(x.^2));
end
I've come up with this plot: