Trying to understand the implementation of boundary conditions in this MATLAB code

조회 수: 6 (최근 30일)
Janee
Janee 2024년 7월 8일
댓글: Umar 2024년 7월 16일
I am following with the textbook: Lloyd N. Trefethen, Spectral Methods in MATLAB, SIAM and trying to understand a very particular MATLAB code. This problem is shown in program 37 and it considers 2nd order wave equation in 2D with periodic boundary conditions in x and Neumann boundary conditions in y:
and the boundary conditions:
So the code is:
%x variable in [-A,A], Fourier
A=3; Nx=50; dx =2*A/Nx; x= -A+dx*(1:Nx)';
D2x = (pi/A)^2*toeplitz([-1/(3*(dx/A)^2)-1/6 ...
0.5*(-1).^(2:Nx)./sin((pi*dx/A)*(1:Nx-1)/2).^2]);
%y variable in [-1,1], chebyshev:
Ny=15;
[Dy,y] = cheb(Ny);
D2y=Dy^2;
BC=-Dy([1 Ny+1],[1 Ny+1])\Dy([1 Ny+1],2:Ny); %Homogenous Neumann BCs for |y|=1
%Grid and initial data:
[xx,yy] = meshgrid(x,y);
vv=exp(-8*((xx+1.5).^2 + yy.^2));
dt = 5/(Nx+Ny^2);
vvold = exp(-8*((xx+dt+1.5).^2+yy.^2));
%Time stepping by leap frog forula:
dt = 5/(Nx+Ny^2);clf; plotgap=round(2/dt); dt=2/plotgap;
for n=0:2*plotgap
t=n*dt;
if rem(n+.5,plotgap)<1
subplot(3,1,n/plotgap+1), mesh(xx,yy,vv), view(-10,60)
colormap([0 0 0])
text(-2.5,1,.5,['t=' num2str(t)],'fontsize',18),,grid off, drawnow
end
vvnew= 2*vv - vvold + dt^2*(vv*D2x+D2y*vv);
vvold = vv; vv = vvnew;
vv([1 Ny+1],:) = BC*vv(2:Ny,:); %Neumann BCs for |y|=1
%first row and last row in vv = BC x
%From Program 33
end
Now, I have a similar problem where I am trying to reproduce the exact BCs for a 2D Poisson's equation/problem. What I am struggling to understand is this line:
BC=-Dy([1 Ny+1],[1 Ny+1])\Dy([1 Ny+1],2:Ny); %Homogenous Neumann BCs for |y|=1
I am not sure what is the author doing here so I can reproduce these exact BCs in my code. My understanding is we want to replace the first/last rows of D2 with values of first/last rows of D and set them to zero? Meaning we want to set the values if the first derivative to zero? Is this correct or am I misunderstanding the syntax. Thanks.
The Cheb function:
function [ D, x ] = cheb ( N )
if ( N == 0 )
D = 0.0;
x = 1.0;
return
end
x = cos ( pi * ( 0 : N ) / N )';
c = [ 2.0; ones(N-1,1); 2.0 ] .* (-1.0).^(0:N)';
X = repmat ( x, 1, N + 1 );
dX = X - X';
% Set the off diagonal entries.
D =( c * (1.0 ./ c )' ) ./ ( dX + ( eye ( N + 1 ) ) );
% Diagonal entries.
D = D - diag ( sum ( D' ) );
return
end
  댓글 수: 9
Janee
Janee 2024년 7월 16일
"It's also worth noting that the warning message may not necessarily indicate a problem with your code"
I believe you are right, sense I am able to "apply" the BCs in a different manner to get rid of the error. I think this solves my issue. However, I tried using my simple 1D example to expand it on a 2D example, but I am failing to move from a 1D to 2D Neumann BCs and having an issue with MATALB syntax.
The 2D problem solves for 2D linear Poisson's equation with periodic BCs along x and Neumann BCs along y and I am trying to take what I learned from 1D Poisson's solver with Neumann BCs and apply it here.
2D example similar to above 1D case:
clearvars; clc; close all;
Nx = 2;
Ny = 10;
Lx =3;
kx = fftshift(-Nx/2:Nx/2-1); % wave number vector
dx = Lx/Nx; % Need to calculate dx
ksqu = (sin( kx * dx/2)/(dx/2)).^2 ;
kx = sin(kx * dx) / dx;
%-----------
xi_x = (2*pi)/Lx;
ksqu4inv = ksqu;
%helps with error: matrix ill scaled because of 0s
ksqu4inv(abs(ksqu4inv)<1e-14) =1e-6;
xi = ((0:Nx-1)/Nx)*(2*pi);
x = xi/xi_x;
Igl = speye(Ny+1);
div_x_act_on_grad_x = -Igl;
ylow = -1;
yupp =1;
Ly = (yupp-ylow);
eta_ygl = 2/Ly;
[D,ygl] = cheb(Ny);
ygl = (1/2)*(((yupp-ylow)*ygl) + (yupp+ylow));
D = D*eta_ygl;
D2 = D*D;
D2([1 Ny+1],:) = D([1 Ny+1],:); %take 1st and last row of D2 and replace it with first and last row of D
[X,Y] = meshgrid(x,ygl);
%linear Poisson solved iteratively
%ZNy represents the operation of setting the boundary values of y component
%to zero:
ZNy = diag([0 ones(1,Ny-1) 0]);
div_y_act_on_grad_y = D2*ZNy;
u =-Y + Y.^3/3 ;
uh = fft(u,[],2);
duxk=(kx*1i*xi_x) .*uh;
du2xk = (kx*1i*xi_x) .*duxk;
duyk = D *uh;
du2yk = D *duyk;
n = ones(size(u));
invnek = fft(1./n,[],2);
nh = fft(n,[],2);
dnhdxk = (kx*1i*xi_x) .*nh;
dnhdyk =D * nh;
puhnhk = dnhdxk .* duxk;
pduhdxdnhdxk = dnhdyk .* duyk;
pduhdx2nhk = nh .* du2xk;
pnhdudx2k = nh .*du2yk;
NumSourcek =puhnhk + pduhdxdnhdxk + pduhdx2nhk + pnhdudx2k;
uold = ones(size(u));
uoldk = fft(uold,[],2);
err_max =1e-8;
max_iter = 500;
Sourcek = NumSourcek;
for iterations = 1:max_iter
phikmax_old = max(max(abs(uoldk)));
duhdxk = (kx*1i*xi_x) .*uoldk;
gradNgradUx = dnhdxk .* duhdxk;
duhdyk = (D) *uoldk ;
gradNgradUy = dnhdyk .* duhdyk;
RHSk = Sourcek - (gradNgradUx + gradNgradUy);
Stilde = invnek .* RHSk;
for m = 1:length(kx)
L = div_x_act_on_grad_x * (ksqu4inv(m)*xi_x)+ div_y_act_on_grad_y;
unewh(:,m) = L\(Stilde(:,m));
end
%enforce BCs, instead of [0;Stilde(2:N);0] in 1D
unewh=[zeros(1,Nx); unewh(2:Ny,:); zeros(1,Nx)];
phikmax = max(max(abs(unewh)));
if phikmax < err_max
it_error = err_max /2;
else
it_error = abs( phikmax - phikmax_old) / phikmax;
end
if it_error < err_max
break;
end
uoldk = unewh;
end
unew = real(ifft(unewh,[],2));
DEsol = unew - u;
DE = max(max(abs(DEsol)));
figure
surf(X, Y, unew-max(max(unew)));
colorbar;
title('Numerical solution of \nabla \cdot (n \nabla u) = s in 2D');
xlabel('x'); ylabel('y'); zlabel('u_{numerical}');
figure
surf(X, Y, u-max(max(u)));
colorbar;
title('Exact solution of \nabla \cdot (n \nabla u) = s in 2D');
xlabel('x'); ylabel('y'); zlabel('u_{exact}');
But this does NOT set the values of the first derivative at +/-1 to zero but the values of u(x,y) to zero instead!! why is that?
The Cheb function
function [ D, x ] = cheb ( N )
if ( N == 0 )
D = 0.0;
x = 1.0;
return
end
x = cos ( pi * ( 0 : N ) / N )';
c = [ 2.0; ones(N-1,1); 2.0 ] .* (-1.0).^(0:N)';
X = repmat ( x, 1, N + 1 );
dX = X - X';
% Set the off diagonal entries.
D =( c * (1.0 ./ c )' ) ./ ( dX + ( eye ( N + 1 ) ) );
% Diagonal entries.
D = D - diag ( sum ( D' ) );
return
end
Umar
Umar 2024년 7월 16일

Hi Janee,

Try to modify the differentiation matrix calculation within the Cheb function, (Reason: The Cheb function you are using is setting the values of u(x, y) to zero instead). I just made the modification in your Cheb function, here is revised version,

function [D, x] = cheb(N)

    if (N == 0)
        D = 0.0;
        x = 1.0;
        return
    end
    x = cos(pi * (0:N) / N)';
    c = [2.0; ones(N-1, 1); 2.0] .* (-1.0).^(0:N)';
    X = repmat(x, 1, N + 1);
    dX = X - X';
    % Set the off-diagonal entries.
    D = (c * (1.0 ./ c)') ./ (dX + eye(N + 1));
    % Modify diagonal entries for enforcing boundary conditions on first derivative.
    D(1, :) = zeros(1, N + 1);
    D(N + 1, :) = zeros(1, N + 1);
    % Update diagonal entries.
    D = D - diag(sum(D'));
    return
end

By incorporating modification of diagonal entries for enforcing boundary conditions on first derivative into your Cheb function, you can make sure that the values of the first derivative at +/-1 are correctly set to zero as intended. This modification will help you enforce the appropriate boundary conditions for the first derivative in your numerical solution code.Hope, now all your issues have been resolved. Please let me know if you have any further questions.

댓글을 달려면 로그인하십시오.

답변 (0개)

카테고리

Help CenterFile Exchange에서 Signal Generation and Preprocessing에 대해 자세히 알아보기

태그

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by