Non homogeneous heat equation - matlab

I have this code which solves the heat equation with non homogeneous boundary conditons:
$$u_t=ku_{xx}$$ where k is the diffusion coefficient
but now I want to add a constant which makes the equation non homogeneous, like this:
$$u_t=ku_{xx}+h$$
function [u,er]=ftcs(t0,tf,nt,a,b,nx,ci,cca,ccb,dif,cada,sol)
% explicit method
%u solution
%er vector error
%t0 y tf time limits
%nt
%nx
%a b x value
%ci initial condition
%cca y ccb boundary conditions
%dif diffusion coefficient
%cada time lapse
%sol solution if it's known
x=linspace(a,b,nx); x=x'; dx=x(2)-x(1); %h
t=linspace(t0,tf,nt); t=t'; dt=t(2)-t(1); %k
r=dt/dx^2*dif;
if r>.5
clc
disp('stability not satisfied')
pause
end
di=1-2*r;
cca=inline(cca,'t');
ccb=inline(ccb,'t');
A=diag(di*ones(nx-2,1))+diag(r*ones(nx-3,1),1)+diag(r*ones(nx-3,1),-1);
A=[[r;zeros(nx-3,1)] A [zeros(nx-3,1);r]];
ci=vectorize(inline(ci,'x'));
u=ci(x); % vectorwith a solution for t=0, initial condition
gra=plot(x,u);
axis([a b min(u) max(u)])
pause
z=u;
u(1)=cca(t(1));
u(end)=ccb(t(1));
for i=1:nt-1;
u=A*u;
u=[cca(t(i+1)); u ; ccb(t(i+1))];
if mod(i,cada)==0
set(gra,'ydata',u');
pause(.1)
z(:,end+1)=u;
end
end
if nargin==12 & nargout==2
sol=vectorize(inline(sol,'x','t'));
er=u-sol(x,tf);
end
pause
figure
surfc(z);shading interp; colormap(hot);set(gca,'ydir','reverse');
rotate3d

Related

Encoding system of differential equations into a vector and approximate solutions

I am trying to solve a system of differential equations by the Euler's method. First, I have encoded my system into a vector. Then I pass the initial conditions to the function ode_Euler.
However, there's somehting wrong about my attempt. I am getting this error:
>> nm06p03a
Unable to perform assignment because the size of the left side is 1-by-2 and the size of the right side is 2-by-2.
Error in ode_Euler (line 11)
y(k+1,:)= y(k,:) +h*feval(f,t(k),y(k,:));
Error in nm06p03a (line 12)
tic, [tE,xE]=ode_Euler(f,tspan,x0,N); t_Euler=toc;
This is my code so far:
clear, clf
f=#(t,x)[-x(2)+x(1)*x(2); x(1)-(0.5.*x(1).^2)+(0.5.*x(2).^2)]; %Encoding system of differential equations into a vector
t0=0; tf=10;
tspan=[t0 tf];
N=100;
x0s=[0.2 0]; % A matrix consisting of initial points
for iter=1:size(x0s,1)
x0=x0s(iter,:);
tic, [tE,xE]=ode_Euler(f,tspan,x0,N); t_Euler=toc;
subplot(220+iter),
plot(tE,xE,'r:')
legend('ode_ Euler')
end
Here is the Euler's method:
function [t,y]=ode_Euler(f,tspan,y0,N)
if nargin<4|N<=0, N=100; end
if nargin<3, y0=0; end
h=(tspan(2)-tspan(1))/N;
t=tspan(1)+[0:N]'*h;
y(1,:)=y0(:)'; %make it a row vector
for k=1:N
y(k+1,:)= y(k,:) +h*feval(f,t(k),y(k,:));
end
When I use this other method ode_Heun, I get the same error:
function [t,y]=ode_Heun(f,tspan,y0,N)
if nargin<4|N<=0, N=100; end
if nargin<3, y0=0; end
h=(tspan(2)-tspan(1))/N; % Step-size
t=tspan(1)+[0:N]'*h; % Time vector
y(1,:)=y0(:)'; % make the initial value a row vector
for k=1:N
fk= feval(f,t(k),y(k,:)); y(k+1,:)= y(k,:)+h*fk; % Eq.(6.2.3)
y(k+1,:)= y(k,:) +h/2*(fk +feval(f,t(k+1),y(k+1,:))); % Eq.(6.2.4)
end
Can I get some help to understand the problem with my code?
y(k,:) is a row vector, while the return value of f is a column vector. Per broadcasting rules the sum of a row and a column vector is a matrix as the sum of the matrices of repeated row and column vectors.
This is not very logical in the context of vector and matrix operations, but can make sense in the processing of (finite) sequences of vectors. Unfortunately that distinction is not realized and enforced in the type system.

how to replace the ode45 method with the runge-kutta in this matlab?

I tried everything and looked everywhere but can't find any solution for my question.
clc
clear all
%% Solving the Ordinary Differential Equation
G = 6.67408e-11; %Gravitational constant
M = 10; %Mass of the fixed object
r = 1; %Distance between the objects
tspan = [0 100000]; %Time Progression from 0 to 100000s
conditions = [1;0]; %y0= 1m apart, v0=0 m/s
F=#(t,y)var_r(y,G,M,r);
[t,y]=ode45(F,tspan,conditions); %ODE solver algorithm
%%part1: Plotting the Graph
% plot(t,y(:,1)); %Plotting the Graph
% xlabel('time (s)')
% ylabel('distance (m)')
%% part2: Animation of Results
plot(0,0,'b.','MarkerSize', 40);
hold on %to keep the first graph
for i=1:length(t)
k = plot(y(i,1),0,'r.','MarkerSize', 12);
pause(0.05);
axis([-1 2 -2 2]) %Defining the Axis
xlabel('X-axis') %X-Axis Label
ylabel('Y-axis') %Y-Axis Label
delete(k)
end
function yd=var_r(y,G,M,r) %function of variable r
g = (G*M)/(r + y(1))^2;
yd = [y(2); -g];
end
this is the code where I'm trying to replace the ode45 with the runge kutta method but its giving me errors. my runge kutta function:
function y = Runge_Kutta(f,x0,xf,y0,h)
n= (xf-x0)/h;
y=zeros(n+1,1);
x=(x0:h:xf);
y(1) = y0;
for i=1:n
k1 = f(x(i),y(i));
k2= f(x(i)+ h/2 , y(i) +h*(k1)/2);
y(i+1) = y(i)+(h*k2);
end
plot(x,y,'-.M')
legend('RKM')
title ('solution of y(x)');
xlabel('x');
ylabel('y(x)')
hold on
end
Before converting your ode45( ) solution to manually written RK scheme, it doesn't even look like your ode45( ) solution is correct. It appears you have a gravitational problem set up where the initial velocity is 0 so a small object will simply fall into a large mass M on a line (rectilinear motion), and that is why you have scalar position and velocity.
Going with this assumption, r is something you should be calculating on the fly, not using as a fixed input to the derivative function. E.g., I would have expected something like this:
F=#(t,y)var_r(y,G,M); % get rid of r
:
function yd=var_r(y,G,M) % function of current position y(1) and velocity y(2)
g = (G*M)/y(1)^2; % gravity accel based on current position
yd = [y(2); -g]; % assumes y(1) is positive, so acceleration is negative
end
The small object must start with a positive initial position for the derivative code to be valid as you have it written. As the small object falls into the large mass M, the above will only hold until it hits the surface or atmosphere of M. Or if you model M as a point mass, then this scheme will become increasingly difficult to integrate correctly because the acceleration becomes large without bound as the small mass gets very close to the point mass M. You would definitely need a variable step size approach in this case. The solution becomes invalid if it goes "through" mass M. In fact, once the speed gets too large the whole setup becomes invalid because of relativistic effects.
Maybe you could explain in more detail if your system is supposed to be set up this way, and what the purpose of the integration is. If it is really supposed to be a 2D or 3D problem, then more states need to be added.
For your manual Runge-Kutta code, you completely forgot to integrate the velocity so this is going to fail miserably. You need to carry a 2-element state from step to step, not a scalar as you are currently doing. E.g., something like this:
y=zeros(2,n+1); % 2-element state as columns of the y variable
x=(x0:h:xf);
y(:,1) = y0; % initial state is the first 2-element column
% change all the scalar y(i) to column y(:,i)
for i=1:n
k1 = f(x(i),y(:,i));
k2= f(x(i)+ h/2 , y(:,i) +h*(k1)/2);
y(:,i+1) = y(:,i)+(h*k2);
end
plot(x,y(1,:),'-.M') % plot the position part of the solution
This is all assuming the f that gets passed in is the same F you have in your original code.
y(1) is the first scalar element in the data structure of y (this counts in column-first order). You want to generate in y a list of column vectors, as your ODE is a system with state dimension 2. Thus you need to generate y with that format, y=zeros(length(x0),n+1); and then address the list entries as matrix columns y(:,1)=x0 and the same modification in every place where you extract or assign a list entry.
Matlab introduce various short-cuts that, if used consequently, lead to contradictions (I think the script-hater rant (german) is still valid in large parts). Essentially, unlike in other systems, Matlab gives direct access to the underlying data structure of matrices. y(k) is the element of the underlying flat array (that is interpreted column-first in Matlab like in Fortran, unlike, e.g., Numpy where it is row-first).
Only the two-index access is to the matrix with its dimensions. So y(:,k) is the k-th matrix column and y(k,:) the k-th matrix row. The single-index access is nice for row or column vectors, but leads immediately to problems when collecting such vectors in lists, as these lists are automatically matrices.

Problem in 2D heat equation solution using FDM in Matlab

I am trying to solve the 2D time dependent heat equation using finite difference method in Matlab. The code is below:
%Spatial variable on x direction
Lx=1;
delta=0.1;
xmin=-Lx/2;
xmax=Lx/2;
Nx=(xmax-xmin)/delta;
x=linspace(xmin,xmax,Nx);
%Spatial variable on y direction
Ly=1;
delta=0.1;
ymin=-Ly/2;
ymax=Ly/2;
Ny=(ymax-ymin)/delta;
y=linspace(ymin,ymax,Ny);
%Total matrix size
N = (Nx * Ny);
%Time variable
dt=0.002;
tmin=0;
tmax=1;
nt=(tmax-tmin)/dt;
tspan=linspace(tmin,tmax,nt);
%Create a meshgrid
[X,Y] = meshgrid(x,y);
% Defining initial state:
T0=exp(-(X.^2+Y.^2));
%reshape the initial condition to a vector
T_reshape = reshape(T0,N,1);
% Constructing the 1D spatial matrix
A=zeros(N,N);
I = eye(N);
%the diagonal elements
for m=1:N %the number of rows
for n=1:N %the number of columns
if (m==n)
A(m,n)=-2/delta^2;
end
%Boundary conditions: A(1,N)==A(N,1)
if(n==N)&&(m==1)
A(m,n)=1;
end
if(n==1)&&(m==N)
A(m,n)=1;
end
end
end
%the off-diagonal elements
for n=1:N-1
A(n+1,n)=1/delta^2; %the value of each lower off-diagonal elements
end
for n=2:N
A(n-1,n)=1/delta^2; %the value of each upper off-diagonal element
end
%create the 2D matrix
B = kron(A,I)+kron(I,A);
% Solve the equation
[Time,Tem]=ode45('dTDistribution',tspan,T_reshape,[],B,delta);
The function that is being called here is as following:
%Define the function
function dT=dTDistribution(tspan,T_reshape,dummy,B,delta)
dT = B.*T_reshape;
end
My problem is that the dimension of my matrix B is different than the dimensions of the initial condition T_reshape, therefore, the multiplication of B.*T_reshape won't be possible. I'm wondering how can I change the dimension of T_reshape to make the multiplication valid. Hope anyone could help.
Thank you.
Thank you for looking at my problem, but I have figured out the mistake in the code. Since A is the 1D matrix, then its size should be either (Nx,Nx) or (Ny,Ny) and then when taking the tensor product to get B the 2D matrix its size will be (N,N). However in the code, A has the size of (N,N) and as a result B is blowing up making the multiplication afterwards not possible.
Thanks.

Solution errors using pdepe to solve heat equation in axisymmetric polar coordinates in a multi-layer annulus

I am trying to model heat conduction in a turn of copper wire. I believe the pdepe function is appropriate as the problem is the forced 1D heat equation in cylindrical polar coordinates.
As recommended elsewhere on this forum, I am modelling the entire composite domain (insulation-copper-insulation) as a single domain with variable properties in space.
The equation in pdepe syntax is (1/alpha(r))du/dt = (1/r)(r*du/dr) + q(r)/k(r)
Temperature u(r,t), diffusivity alpha(r), volumetric heat generation rate q(r), conductivity k(r)
It has external boundary conditions du/dr = 0 (insulated) on the inner surface and k(r)du/dr + h(u-u0) =0 (convective) on the outer surface.
Initial conditions are zero everywhere.
I have compared the output as t --> inf to the analytic steady-state solution (attached), which is completely different. The temperature rise should be of the order 120 deg C in steady state.
Steady State solution profile
Outputs from the code (relevant excerpts attached below) however are all O(1). I would be grateful if anyone could shed some light on what I'm doing wrong or if pdepe is just not appropriate here. With many thanks in advance.
function [sol,systInfo]=ThreeLayerHeat
%uses pdepe()
%% geometry
rInner=0.05;
rOuter=0.1;
tIns=50e-6; %insulation thickness
r2=rInner+tIns; %internal boundaries
r3=rOuter-tIns;
tDomain=rOuter-rInner;
tCond=tDomain-tIns; %one conductor layer
m = 1; %CPCs
%% material properties
%copper
k_cond=394;
rho_cond=8960;
cp_cond=390;
%mica
k_ins=0.5;
rho_ins=2800;
cp_ins=880;
alpha_cond=k_cond/(rho_cond*cp_cond);
alpha_ins=k_ins/(rho_ins*cp_ins);
%%Internal generation
Jlimit=4e6; %4A/mm^2
ACfactor=1.2; %CF design of electrical machines
rho_conductor=1.75e-8; %electrical resistivity Table 9.3 293K %at reference level
%%boundary details
Tinf=0; %fluid temp on outer boundary
h2=100; %HTC on outer boundary
%%Characteristic (Fo) times
tau_chic_cond=tCond^2/alpha_cond;
tau_chic_ins=tIns^2/alpha_ins;
tau_chic_limiting=max(tau_chic_cond,tau_chic_ins);
%%discretisation
%spatial
npoints=50;
x=linspace(rInner,rOuter,npoints);
%ensure mesh points exist at internal boundaries r2 and r3
x=unique(sort(horzcat(x,r2,r3)));
%temporal
nt=10;
nPeriods=50; %how many times limiting (longest) tau (>1 to reach equilibrium)
%linspace
t0=0;
tf=t0+tau_chic_limiting*nPeriods;
t=linspace(t0,tf,nt);
if t0~=0
t=horzcat(0,t); %add 0 padding if doesn't start at 0 to allow initialisation
end
%logspace - uncomment this to use log time
% logi=-2; %initial point
% logf=log10(tf);
% t=logspace(logi,logf,nt);
% t=horzcat(0,t);
%%solve the system
sol= pdepe(m,#pdefun,#pdeic,#pdebc,x,t);
% Extract the first solution component as u.
u = sol(:,:,1);
% A surface plot
surf(x./rOuter,t./tau_chic_limiting,u-Tinf)
title(horzcat('Numerical solution computed with ',num2str(npoints), ' mesh points.'))
xlabel('Nondimensional radial distance r/r_O_u_t_e_r')
ylabel('Limiting Fourier number Fo')
zlabel('Temperature rise T')
set(gca, 'YScale','log') %if logspace used
% A limiting solution profile.
figure
plot(x,u(end,:))
hold on
plot([r2 r2],[0 max(u(end,:))],'--')
plot(x,0,'.')
plot([r3 r3],[0 max(u(end,:))],'--')
hold off
title('Final timestep (Fo \rightarrow \infty) solution')
xlabel('Distance r')
ylabel('T_\infty')
% --------------------------------------------------------------
function [c,f,s] = pdefun(x,t,u,DuDx) %computes cfs
%geometry and material info passed through nesting
%material distribution of alpha, k
if (x>=r2 && x<=r3)
alpha1=alpha_cond;
k=k_cond;
else
alpha1=alpha_ins;
k=k_ins;
end
%define for pdepe
c = 1/alpha1;
%definition of flux term
f = DuDx;
%heating distribution (currently constant with t)
rho_cond_max=rho_conductor; %for invariable resistivity
sigma_cond=1/rho_cond_max; %definition of conductivity = 1/resistivity
qvdot=ACfactor*(Jlimit^2)/sigma_cond; %volumetric heating rate (of conductor)
%source terms: heating only in conductor
s_cond=qvdot/k_cond;
s_ins=0/k_ins;
if (x>=r2 && x<=r3)
s=s_cond;
else
s=s_ins;
end
end
% --------------------------------------------------------------
function u0 = pdeic(x) %ICs
u0 = 0.*x; %starts at zero relative temp
end
% --------------------------------------------------------------
function [pl,ql,pr,qr] = pdebc(xl,ul,xr,ur,t) %BCs
%exterior BCs only
%constants passed through nesting
%nb f is set as du/dx
% %insulated LHS (inner)
pl = 0;
ql = -1*k_ins;
%convective RHS (outer)
pr = -1*h2*(ur-Tinf);
qr = -1*k_ins;
end
%end of nesting
end

Calculate the power in a bow string using matlab

I'm trying to calculate the force in a bow string while using MATLAB's ode45, I have this differential equation
M(x)=d^2y/dx^2 * (1+(dy/dx)^2)^(-3/2)=-q * y where M(x) is the average torque in the bow, q=11.4716, and y(0)=0.3, y'(0)=0 and 0≤ x ≤0.3668
I have calculated the differential equation with ode45 but I have tried to calculate the force with this code;
X=0.3668
tolerance=odeset('Abstol', 1e-9, 'Reltol', 1e-11);
[x,M]=diffekv45(tolerance,X)
force=zeros(length(x),1);
for i=1:length(x)
if x(i)==0
force(i)=0;
else
force(i)=(0.3-M(i,1))./x(i); %%% 0.3-M(i,1) is because it is equilibrium in the %%center of the bow
end
end
totalforce=sum(force);
Line 6 is calculating the torque in all the readings. I suppose that the first element in M is the average torque.
I'm using these functions
function [x,M] = diffekv45(tolerance,X)
u0=[0.3;0];
[x,u]=ode45('M',[0,X],u0,tolerance);
end
function M=M(~,u)
global q
M=[u(2)
-q*u(1)*(1+u(2)^2)^(3/2)];
end
When I calculate the force with a higher or lower tolerans I get a significant higher or lower value of the force. That's why I'm wrong. So how can I calculate the force in the bow string?
You have a 2nd order equation in terms of the displacement, which needs to be split up into two first order equations for use in orde45().
Use a state vector h=[y; diff(y,x)] and create the following differential function for use in ode45()
function hp = deriv(x,h)
y = h(1); %First element of h is the deflection
v = h(2); %Last element of h is the slope
hp = [v; -q*y/(1+v^2)^(-3/2)];
end
and then call
h0 = [0.3; 0];
ode45(deriv, [0,X], h0, tol);