% stove_top_3D_FD.m % % This MATLAB program uses the finite difference method % to solve a 3-D BVP that models heat transfer within % a 3-D stove top element. % % K. Beers. MIT ChE. 12/1/02. v 10/4/03 function iflag_main = stop_top_3D_FD(); iflag_main = 0; % ----- CHECK FOR RESTART ------------------------------------------ % If this is a restart, we do not need to compute matrix again. % Note, that we do not read in old value as initial guess. % We only have restart to test difference solution methods % quickly. isrestart = input('Is this a restart, 0(no) or 1(yes) : '); if(isrestart) load stove_top_3D_FD.mat; % load previous results % Next, choose solver. Either use direct method % (MATLAB elimination solver) or CG-type. isolver = input('Choose direct (0), bicgstab (1), or gmres(2) solver : '); % select preconditioner if(isolver) mode_precond = ... input('Use preconditioner? : none (0), Jacobi (1), or ILU (2)? : '); end if(isolver >= 2) restart = input('Enter RESTART for GMRES solver : '); end if(mode_precond >= 2) mode_fill = ... input('ILU: no-fill (0) or non-zero drop tol (1) : '); if(mode_fill) drop_tol = input('Enter drop tol : '); ILU_Options.droptol = drop_tol; end ILU_Options.milu = 1; ILU_Options.udiag = 1; end else % ----- ENTER SYSTEM PARAMETERS ------------------------------------ sigma = input('Enter sigma (e.g. 1) : '); % Next, set the physical parameters of the % problem. a_geom = input('Enter a (L/D) (e.g. 2/3) : '); % L/D b_geom = input('Enter b (d1/L) (e.g. 0.5) : '); % d1/L % inner radius and thickness of first annular region r1_L = input('Enter r1_L (in. rad. of 1st annulus) (e.g. 0.1) : '); t1_L = input('Enter t1_L (thick. of 1st annulus (e.g. 0.05) : '); % inner radius and thickness of second annular region r2_L = input('Enter r2_L (in. rad. of 2nd annulus) (e.g. 0.25) : '); t2_L = input('Enter t2_L (thick. of 2nd annulus) (e.g. 0.05) : '); % Enter grid information N_xy = input('Enter # of grid points in x and y directions (e.g. 51) : '); x_grid = linspace(0,0.5,N_xy); dx = x_grid(2) - x_grid(1); y_grid = linspace(0,0.5,N_xy); dy = y_grid(2) - y_grid(1); N_z = input('Enter # of grid points in z direction (e.g. 25) : '); % Now, as we expect strongest gradients to occur near surface, we place 1/4 % of the points in the range z =0 to z = -0.2. Nz_up = round(N_z/4); dz_fine = 0.2/(Nz_up-1); z_grid_fine = linspace(0,0.2-dz_fine,Nz_up)'; % place remaining points in lower part of domain z_grid_coarse = linspace(0.2, 1/a_geom,N_z - Nz_up)'; z_grid = [z_grid_fine; z_grid_coarse]; N_z = length(z_grid); % Set total domension of problem Ntot = N_z*(N_xy^2); % total number of grid points disp(['Grid size, N_xy = ', int2str(N_xy), ... ', N_z = ', int2str(N_z), ... ', Ntot = ', int2str(Ntot)]); i_go_on = input('Stop (0) or continue (1)? : '); if(~i_go_on) return; end % Next, choose solver. Either use direct method % (MATLAB elimination solver) or CG-type. isolver = input('Choose direct (0), bicgstab (1), or gmres(2) solver : '); % select preconditioner if(isolver) mode_precond = ... input('Use preconditioner? : none (0), Jacobi (1), or ILU (2)? : '); end if(isolver >= 2) restart = input('Enter RESTART for GMRES solver : '); end if(mode_precond >= 2) mode_fill = ... input('ILU: no-fill (0) or non-zero drop tol (1) : '); if(mode_fill) drop_tol = input('Enter drop tol : '); ILU_Options.droptol = drop_tol; end ILU_Options.milu = 1; ILU_Options.udiag = 1; end % ----- SET MATRIX AND VECTOR FOR PROBLEM --------------------------- % Allocate space for matrix using sparse matrix % notation. Also allocate space for right hand % side vector. A = spalloc(Ntot,Ntot,7*Ntot); b = zeros(Ntot,1); % We now set the linear system grid point by % grid point, starting first with the interior % points. % First, get factors we will need many times factor_x_up = zeros(size(x_grid)); factor_x_lo = zeros(size(x_grid)); for ix=2:(N_xy-1) xmid_up = 0.5*(x_grid(ix+1)+x_grid(ix)); xmid_lo = 0.5*(x_grid(ix)+x_grid(ix-1)); factor_x_up(ix) = 1 / (xmid_up - xmid_lo) / ... (x_grid(ix+1) - x_grid(ix)); factor_x_lo(ix) = 1 / (xmid_up - xmid_lo) / ... (x_grid(ix) - x_grid(ix-1)); end factor_y_up = zeros(size(y_grid)); factor_y_lo = zeros(size(y_grid)); for iy=2:(N_xy-1) ymid_up = 0.5*(y_grid(iy+1)+y_grid(iy)); ymid_lo = 0.5*(y_grid(iy)+y_grid(iy-1)); factor_y_up(iy) = 1 / (ymid_up - ymid_lo) / ... (y_grid(iy+1) - y_grid(iy)); factor_y_lo(iy) = 1 / (ymid_up - ymid_lo) / ... (y_grid(iy) - y_grid(iy-1)); end factor_z_up = zeros(size(z_grid)); factor_z_lo = zeros(size(z_grid)); for iz=2:(N_z-1) zmid_up = 0.5*(z_grid(iz+1)+z_grid(iz)); zmid_lo = 0.5*(z_grid(iz)+z_grid(iz-1)); factor_z_up(iz) = 1 / (zmid_up - zmid_lo) / ... (z_grid(iz+1) - z_grid(iz)); factor_z_lo(iz) = 1 / (zmid_up - zmid_lo) / ... (z_grid(iz) - z_grid(iz-1)); end % Now construct the matrix elements for the % interior point rows from these values. for ix=2:(N_xy-1) for iy=2:(N_xy-1) for iz=2:(N_z-1) % get master label m = calc_label(ix,iy,iz,N_xy,N_z); % set matrix elements for this row % (ix-1,iy,iz) n = calc_label(ix-1,iy,iz,N_xy,N_z); A(m,n) = -factor_x_lo(ix); % (ix+1,iy,iz) n = calc_label(ix+1,iy,iz,N_xy,N_z); A(m,n) = -factor_x_up(ix); % (ix,iy-1,iz) n = calc_label(ix,iy-1,iz,N_xy,N_z); A(m,n) = -factor_y_lo(iy); % (ix,iy+1,iz) n = calc_label(ix,iy+1,iz,N_xy,N_z); A(m,n) = -factor_y_up(iy); % (ix,iy,iz-1) n = calc_label(ix,iy,iz-1,N_xy,N_z); A(m,n) = -factor_z_lo(iz); % (ix,iy,iz+1) n = calc_label(ix,iy,iz+1,N_xy,N_z); A(m,n) = -factor_z_up(iz); % (ix,iy,iz) A(m,m) = factor_x_lo(ix) + factor_x_up(ix) + ... factor_y_lo(iy) + factor_y_up(iy) + ... factor_z_lo(iz) + factor_z_up(iz); % set right hand side vector component H_loc = get_H_heat_region(x_grid(ix),y_grid(iy),z_grid(iz),... a_geom,b_geom,r1_L,t1_L,r2_L,t2_L); b(m) = sigma*H_loc; end end end disp('Finished setting interior matrix/vector'); disp('Setting boundary conditions ...'); mode_BC = 1; % BC # 6 at z = 0 iz=1; for ix=1:N_xy for iy=1:N_xy m = calc_label(ix,iy,iz,N_xy,N_z); A(m,m) = 1; b(m) = 0; end end % BC # 5 at z = N iz = N_z; for ix=1:N_xy for iy=1:N_xy m = calc_label(ix,iy,iz,N_xy,N_z); n1 = calc_label(ix,iy,iz-1,N_xy,N_z); if(mode_BC==0); A(m,m) = 1; A(m,n1) = -1; b(m) = 0; else n2 = calc_label(ix,iy,iz-2,N_xy,N_z); A(m,m)=3; A(m,n1)=-4; A(m,n2)=1; b(m) = 0; end end end % BC # 1 at y = 0 iy = 1; for ix=1:N_xy for iz=2:(N_z-1) m = calc_label(ix,iy,iz,N_xy,N_z); n1 = calc_label(ix,iy+1,iz,N_xy,N_z); if(mode_BC==0); A(m,m) = 1; A(m,n1) = -1; b(m) = 0; else n2 = calc_label(ix,iy+2,iz,N_xy,N_z); A(m,m)=3; A(m,n1)=-4; A(m,n2)=1; b(m) = 0; end end end % BC # 2 at y = 1 iy = N_xy; for ix=1:N_xy for iz=2:(N_z-1) m = calc_label(ix,iy,iz,N_xy,N_z); n1 = calc_label(ix,iy-1,iz,N_xy,N_z); if(mode_BC==0); A(m,m) = 1; A(m,n1) = -1; b(m) = 0; else n2 = calc_label(ix,iy-2,iz,N_xy,N_z); A(m,m)=3; A(m,n1)=-4; A(m,n2)=1; b(m) = 0; end end end % BC # 3 at x = 0 ix = 1; for iy=2:(N_xy-1) for iz=2:(N_z-1) m = calc_label(ix,iy,iz,N_xy,N_z); n1 = calc_label(ix+1,iy,iz,N_xy,N_z); if(mode_BC==0); A(m,m) = 1; A(m,n1) = -1; b(m) = 0; else n2 = calc_label(ix+2,iy,iz,N_xy,N_z); A(m,m)=3; A(m,n1)=-4; A(m,n2)=1; b(m) = 0; end end end % BC # 4 at x = 1 ix = N_xy; for iy=2:(N_xy-1) for iz=2:(N_z-1) m = calc_label(ix,iy,iz,N_xy,N_z); n1 = calc_label(ix-1,iy,iz,N_xy,N_z); if(mode_BC==0); A(m,m) = 1; A(m,n1) = -1; b(m) = 0; else n2 = calc_label(ix-2,iy,iz,N_xy,N_z); A(m,m)=3; A(m,n1)=-4; A(m,n2)=1; b(m) = 0; end end end end % ---- CALLING LINEAR SOLVER ------------------------------ % compute the temperature profile by solving the % linear system % direct solver if(isolver==0) % solve using MATLAB's built-in elimination solver disp('calling direct solver ...'); theta = A\b; % otherwise, use bicgstab solver elseif(isolver==1) tol = 1e-8; maxit = round(1.1*Ntot); % select preconditioner disp('generating precondioner ...'); if(mode_precond==0) disp('calling bicgstab() solver ...'); [theta,iflag,relres,iter] = bicgstab(A,b,tol,maxit); elseif(mode_precond==1) % Jacobi preconditioner M_PC = diag(diag(A)); disp('calling bicgstab() solver ...'); [theta,iflag,relres,iter] = bicgstab(A,b,tol,maxit,M_PC); else if(mode_fill==0) [Linc,Uinc] = luinc(A,'0'); else [Linc,Uinc] = luinc(A,ILU_Options); end disp('calling bicgstab() solver ...'); [theta,iflag,relres,iter] = bicgstab(A,b,tol,maxit,Linc,Uinc); end % report results disp(' '); disp('bicgstab results : '); disp(['iflag = ', int2str(iflag), ', relres = ', num2str(relres), ... ', iter = ', int2str(iter)]); elseif(isolver==2) % GMRES method tol = 1e-8; maxit = round(1.1*Ntot); % select preconditioner disp('generating precondioner ...'); if(mode_precond==0) disp('calling gmres() solver ...'); [theta,iflag,relres,iter] = gmres(A,b,restart,tol,maxit); elseif(mode_precond==1) % Jacobi preconditioner M_PC = diag(diag(A)); disp('calling gmres() solver ...'); [theta,iflag,relres,iter] = gmres(A,b,restart,tol,maxit,M_PC); else if(mode_fill==0) [Linc,Uinc] = luinc(A,'0'); else [Linc,Uinc] = luinc(A,ILU_Options); end disp('calling gmres() solver ...'); [theta,iflag,relres,iter] = gmres(A,b,restart,tol,maxit,Linc,Uinc,theta_guess); end % report results disp(' '); disp('gmres results : '); disp(['iflag = ', int2str(iflag), ', relres = ', num2str(relres), ... ', iter = ', int2str(iter)]); end % for isolver % ---- PLOTTING RESULTS ------------------------------ % Now, plot results for plane at y = 0 iy = 1; Theta_slice = zeros(N_z,N_xy); for ix=1:N_xy for iz=1:N_z % get local temperature m = calc_label(ix,iy,iz,N_xy,N_z); Theta_slice(iz,ix) = theta(m); % check if point is within heat generating region if(iz==1) H_loc = get_H_heat_region(x_grid(ix),y_grid(iy),... z_grid(iz),a_geom,b_geom, ... r1_L,t1_L,r2_L,t2_L); S_slice(iz,ix) = sigma*H_loc; else % if interior point S_slice(iz,ix) = b(m); end end end % make plot of temperature distribution disp('Plotting temperature distribution ...'); figure; contourf(x_grid,-z_grid,Theta_slice,20); colorbar; xlabel('\chi'); ylabel('\zeta'); title_phrase = ['\theta(\chi,\eta,\zeta), \sigma = ', ... num2str(sigma), ', N_{xy} = ', int2str(N_xy), ... ', N_z = ', int2str(N_z)]; title(title_phrase); theta_max = max(max(Theta_slice)); gtext(['\theta_{max} = ', num2str(theta_max)]); % make plot of local heat generation rate disp('Plotting heat generation rate ...'); figure; contourf(x_grid,-z_grid,S_slice,20); colorbar; xlabel('\chi'); ylabel('\zeta'); title_phrase = ['S(\chi,\eta,\zeta), \sigma = ', ... num2str(sigma), ... ', N_{xy} = ', int2str(N_xy), ... ', N_z = ', int2str(N_z)]; title(title_phrase); % make plot of heat flux at the surface disp('Plotting heat flux at surface ...'); Theta_flux_surf = zeros(N_xy,N_xy); for ix=1:N_xy for iy=1:N_xy m = calc_label(ix,iy,1,N_xy,N_z); n1 = calc_label(ix,iy,2,N_xy,N_z); n2 = calc_label(ix,iy,3,N_xy,N_z); Theta_flux_surf(iy,ix) = (1/2/dz_fine)*... (-theta(n2) + 4*theta(n1) - 3*theta(m)); end end figure; contourf(x_grid,y_grid,Theta_flux_surf,20); colorbar; xlabel('\chi'); ylabel('\eta'); title('Surface heat flux'); % compute total heat flux using trapezoid rule DI_y = zeros(size(x_grid)); for ix=1:N_xy % get all values at this x value integrand_y = Theta_flux_surf(ix,:); DI_y(ix) = trapz(y_grid,integrand_y'); end total_flux = trapz(x_grid,DI_y); total_flux = total_flux * 4; % correct for quadrant domain disp(' '); disp(['Total heat flux out of surface = ', ... num2str(total_flux)]); % calculate total heat generation rate vol_an1 = b_geom*pi*((r1_L+t1_L)^2 - r1_L^2); vol_an2 = b_geom*pi*((r2_L+t2_L)^2 - r2_L^2); total_heat_gen = (vol_an1 + vol_an2)*sigma; disp(['Total heat generation rate = ', ... num2str(total_heat_gen)]); % add results to plot gtext({['Tot. heat flux out = ', num2str(total_flux)], ... ['Tot. heat gen. rate = ', num2str(total_heat_gen)]}); % extract solution into 3D array Theta_3D = zeros(N_xy,N_xy,N_z); %[X,Y,Z] = meshgrid(x_grid,y_grid,z_grid); for ix=1:N_xy for iy=1:N_xy for iz=1:N_z m = calc_label(ix,iy,iz,N_xy,N_z); Theta_3D(ix,iy,iz) = theta(m); end end end % generate a few slices at points of interest [X,Y,Z] = meshgrid(x_grid,y_grid,z_grid); % mid-slice in x figure; [SY,SZ] = meshgrid(y_grid,z_grid); SX = x_grid(round(N_xy/2))*ones(size(SY)); slice(X,Y,Z,Theta_3D,SX,SY,SZ); hold on; % mid-slice in y [SX,SZ] = meshgrid(x_grid,z_grid); SY = y_grid(round(N_xy/2))*ones(size(SX)); slice(X,Y,Z,Theta_3D,SX,SY,SZ); % mid-slice in z [SX,SY] = meshgrid(x_grid,y_grid); SZ = z_grid(round(N_z/2))*ones(size(SY)); slice(X,Y,Z,Theta_3D,SX,SY,SZ); xlabel('x'); ylabel('y'); zlabel('z'); colorbar; % save results to disk save stove_top_3D_FD.mat; iflag_main = 1; return; % ===================================================== % This function computes the location in the master % vector of the temperature at grid point (i,j,k) function label = calc_label(ix,iy,iz,N_xy,N_z); label = (iz-1)*N_xy*N_xy + (ix-1)*N_xy + iy; return; % ===================================================== % This function checks to see if the local point is % within a heat generating region. If so, the function % returns a 1, else a 0. function [H_loc,iflag] = ... get_H_heat_region(x,y,z,a_geom,b_geom, ... r1_L,t1_L,r2_L,t2_L); iflag = 0; % First, check to see whether the point is % close enough to the surface. if(z > b_geom) H_loc = 0; return; end % Next, compute radius in (x,y) polar coordinates r = sqrt(x^2 + y^2); % If in first annular region if(and((r >= r1_L),(r <= (r1_L+t1_L)))) H_loc = 1; return; % else if in second annular region elseif(and((r >= r2_L),(r <= (r2_L+t2_L)))) H_loc = 1; return; else H_loc = 0; end iflag = 1; return;