|
rbmatlab 0.10.01
|
00001 function num_flux_mat = fv_num_diff_flux(model, model_data, U, NU_ind) 00002 %function num_flux_mat = fv_num_diff_flux(model, model_data, U, [NU_ind]) 00003 % 00004 % function computing a numerical diffusive flux matrix for a convection 00005 % diffusion problem. Dirichlet boundary treatment is performed, but 00006 % neuman values are set to nan, this must be handled by calling function. 00007 % 00008 % In case of gradient_approximation for discretization of a 00009 % 'gradient_tensor' the parameter NU_ind is necessary, if the gradient 00010 % shall only be approximated on the local grid coordinates given by NU_ind. 00011 % 00012 % fields of num_flux: 00013 % epsilon: diffusion coefficient bound 00014 % G: the matrix of numerical flux values across the edges. 00015 % boundary treatment is performed as follows: 00016 % in dirichlet-boundary edges, the neighbour-values are simply set 00017 % to this value and the flux is computed. 00018 % 00019 % required fields of model: 00020 % name_diffusive_num_flux : 'none', 'gradient', 'gradient2' 00021 % 'gradient': use edge-midpoints for diffusivity 00022 % discretization 00023 % 'gradient2': use two element-cog values 00024 % for diffusivity discretization 00025 % instead of edge-midpoint value 00026 % 'gradient_tensor': interpolate a gradient at each edge center 00027 % and left-multiply it with a 'tensor' 00028 % matrix calculated by diffusivity_tensor. 00029 % model for diffusivity_tensor must be 00030 % given too in this case. 00031 % plus additional fields required by dirichlet_values 00032 00033 % Bernard Haasdonk 10.4.2006 00034 00035 grid = model_data.grid; 00036 00037 if isempty(NU_ind) 00038 NU_ind = 1:grid.nelements; 00039 end 00040 00041 %nu_ind_length = length(NU_ind); 00042 00043 num_flux_mat = []; 00044 num_flux_mat.epsilon = 0; 00045 num_flux_mat.G = zeros(size(grid.NBI)); 00046 00047 % determine index sets of boundary types 00048 real_NB_ind = find(grid.NBI>0); 00049 % NBIind = grid.NBI(real_NB_ind); 00050 % INBind = grid.INB(real_NB_ind); 00051 % NB_real_NB_ind = sub2ind(size(grid.NBI),NBIind,INBind); 00052 00053 dir_NB_ind =find(grid.NBI == -1); 00054 neu_NB_ind =find(grid.NBI == -2); 00055 00056 if model.verbose >= 29 00057 disp(['found ',num2str(length(real_NB_ind)),' non-boundary edges.']) 00058 disp(['found ',num2str(length(dir_NB_ind)),' dirichlet-boundary edges.']) 00059 disp(['found ',num2str(length(neu_NB_ind)),' neumann-boundary edges.']) 00060 end; 00061 00062 %%%%%%%%%%%%%%%%%%% diffusive numerical flux %%%%%%%%%%%%%%%%%%%%%%%%%% 00063 if isequal(model.name_diffusive_num_flux,'none') 00064 % set output to zero instead of nan 00065 num_flux_mat.G(:) = 0; 00066 elseif isequal(model.name_diffusive_num_flux,'gradient') 00067 % 1. method: evaluation of diffusivity in edge-circumcenter-intersections 00068 diff = model.diffusivity_ptr([grid.ESX(:),grid.ESY(:)],model); 00069 K = reshape(diff.K,size(grid.ESX)); 00070 nfaces = size(grid.NBI,2); 00071 UU = repmat(U,1,nfaces); 00072 % matrix with the neighbouring values products 00073 UNB = nan * ones(size(UU)); 00074 UNB(real_NB_ind) = UU(grid.NBI(real_NB_ind)); 00075 00076 % set real neighbour values 00077 num_flux_mat.G(real_NB_ind) = ... 00078 K(real_NB_ind).*grid.EL(real_NB_ind).*(grid.DS(real_NB_ind).^(-1).* ... 00079 (UU(real_NB_ind)- ... 00080 UNB(real_NB_ind))); 00081 00082 % determine dirichlet-boundary values as required by convective 00083 % and diffusive flux. 00084 if ~isempty(dir_NB_ind) 00085 Xdir = grid.ESX(dir_NB_ind); 00086 Ydir = grid.ESY(dir_NB_ind); 00087 Udir = model.dirichlet_values_ptr([Xdir,Ydir],model); 00088 Kdir = K(dir_NB_ind); 00089 % determine distances circumcenter to edge-midpoint for 00090 % gradient approximation 00091 %[dir_NB_i,dir_NB_j] = ind2sub(size(UU),dir_NB_ind); 00092 %Ddir = sqrt((grid.ESX(dir_NB_ind)-grid.CX(dir_NB_i)).^2 + ... 00093 % (grid.ESY(dir_NB_ind)-grid.CY(dir_NB_i)).^2); 00094 % set dirichlet neighbour values 00095 %num_flux_mat.G(dir_NB_ind) = ... 00096 % grid.EL(dir_NB_ind).*(Ddir.^(-1).* Kdir .*(UU(dir_NB_ind)-Udir)); 00097 % keyboard 00098 num_flux_mat.G(dir_NB_ind) = ... 00099 grid.EL(dir_NB_ind).*(grid.DS(dir_NB_ind).^(-1).* Kdir ... 00100 .*(UU(dir_NB_ind)-Udir)); 00101 end; 00102 00103 % set diffusivity bound 00104 num_flux_mat.epsilon = diff.epsilon; 00105 00106 elseif isequal(model.name_diffusive_num_flux,'gradient2') 00107 % 2. method: vector evaluating the diffusivity in all element 00108 % circumcenters 00109 diff = model.diffusivity_ptr([grid.SX,grid.SY],model); 00110 00111 nfaces = size(grid.NBI,2); 00112 UK = repmat(diff.K.*U,1,nfaces); 00113 % matrix with the neighbouring diffusivity products 00114 UKNB = nan * ones(size(UK)); 00115 UKNB(real_NB_ind) = UK(grid.NBI(real_NB_ind)); 00116 00117 % set real neighbour values 00118 num_flux_mat.G(real_NB_ind) = ... 00119 grid.S(real_NB_ind).*(grid.DS(real_NB_ind).^(-1).* ... 00120 (UK(real_NB_ind)- ... 00121 UKNB(real_NB_ind))); 00122 00123 % determine dirichlet-boundary values as required by convective 00124 % and diffusive flux. 00125 if ~isempty(dir_NB_ind) 00126 Xdir = grid.ESX(dir_NB_ind); 00127 Ydir = grid.ESY(dir_NB_ind); 00128 Udir = dirichlet_values(model,Xdir,Ydir); 00129 Kdir = diffusivity(model,Xdir, Ydir); 00130 % determine distances COG to edge-midpoint for gradient approximation 00131 %[dir_NB_i,dir_NB_j] = ind2sub(size(UK),dir_NB_ind); 00132 %Ddir = sqrt((grid.Sx(dir_NB_ind)-grid.CX(dir_NB_i)).^2 + ... 00133 % (grid.Sy(dir_NB_ind)-grid.CY(dir_NB_i)).^2); 00134 00135 % set dirichlet neighbour values 00136 %num_flux_mat.G(dir_NB_ind) = ... 00137 % grid.S(dir_NB_ind).*(Ddir.^(-1).* (UK(dir_NB_ind)-Udir.*Kdir.K)); 00138 num_flux_mat.G(dir_NB_ind) = ... 00139 grid.EL(dir_NB_ind).*(grid.DS(dir_NB_ind).^(-1).* ... 00140 (UK(dir_NB_ind)-Udir.*Kdir.K)); 00141 end; 00142 00143 % set diffusivity bound 00144 num_flux_mat.epsilon = diff.epsilon; 00145 00146 elseif isequal(model.name_diffusive_num_flux, 'gradient_tensor') 00147 % get values in centers of the cells adjacent to the edge an the edges 00148 % corner points. The corner values are computed by a 'weighted' average 00149 % over the four adjacent cells. Then do an lsq approximation of the 00150 % face the four points lie on. QUESTION: How can this be done in 3d and 00151 % on general grids? 00152 if isequal(model.gridtype, 'rectgrid') 00153 G_with_nans = zeros(size(num_flux_mat.G)); 00154 00155 for edge = 1:4 00156 diff = model.diffusivity_tensor_ptr([grid.ECX(NU_ind,edge),grid.ECY(NU_ind,edge)], U, model, 1); 00157 diff_k = model.diffusivity_ptr([grid.ECX(NU_ind,edge),grid.ECY(NU_ind,edge)], model, U); 00158 % construct the diffusivity matrix D for current edge 00159 % diff1 = diff.K1; 00160 % diff2 = diff.K2; 00161 00162 % [tmpgrad,bdir] = gradient_approx_matrix(model,model_data,NU_ind,edge); 00163 [tmpgrad] = gradient_approx(model,model_data,U,NU_ind,edge); 00164 00165 % tmp2 stores the matrix vector product of 'diffusion tensor x 00166 % gradient' 00167 % tmpgrad = tmpgrad(NU_ind,:); 00168 vlen = size(tmpgrad,1); 00169 tmpgrad = reshape(tmpgrad',2*vlen,1); 00170 00171 % tmpggrad = model.gravity*repmat([0;grid.EL(1,2)],vlen,1); 00172 00173 tmp1 = diff_k.K * diff.K; 00174 tmp2 = tmp1 * tmpgrad; 00175 % tmp22 = tmp1 * tmpgrad2; 00176 % tmp2 = [ sum(diff1 .* tmpgrad, 2), ... 00177 % sum(diff2 .* tmpgrad, 2) ]; 00178 00179 % if edge == 2 || edge == 4 00180 % quiver(grid.ECX(:,edge),grid.ECY(:,edge), tmpgrad(:,1), tmpgrad(:,2)); 00181 % hold on; 00182 % quiver(grid.ECX(:,edge),grid.ECY(:,edge), tmp2(:,1), tmp2(:,2)); 00183 % hold off; 00184 % keyboard; 00185 % end 00186 00187 tmp2 = reshape(tmp2, 2, vlen)'; 00188 00189 % M = length(NU_ind); 00190 % offset = kron(M,NU_ind)-M; 00191 % indices = repmat(offset',M,1)+repmat(NU_ind,1,M); 00192 00193 G_with_nans(NU_ind,edge) = sum(tmp2 .* [ grid.NX(NU_ind,edge), grid.NY(NU_ind,edge) ], 2); 00194 % helper = sparse([1:nu_ind_length,1:nu_ind_length], ... 00195 % [2*(1:nu_ind_length)-1, 2*(1:nu_ind_length)], ... 00196 % reshape( [grid.NX(NU_ind,edge), grid.NY(NU_ind,edge)], 1, 2*nu_ind_length ) ); 00197 % G_with_nans_temp = helper * tmp2; 00198 % G_with_nans_temp = G_with_nans_temp * U + helper * tmp1 * bdir; 00199 % max(max(G_with_nans_temp - G_with_nans(NU_ind, edge))) 00200 % G_with_nans(NU_ind, edge) = G_with_nans_temp * U + helper * tmp1 * bdir; 00201 end 00202 G_with_nans = G_with_nans .* grid.EL; 00203 num_flux_mat.G(real_NB_ind) = G_with_nans(real_NB_ind); 00204 num_flux_mat.G(dir_NB_ind) = G_with_nans(dir_NB_ind); 00205 00206 num_flux_mat.epsilon = max(max(num_flux_mat.G)); 00207 else 00208 error(['gradient_tensor is not implemented for specified gridtype ', ... 00209 model.gridtype]); 00210 end 00211 else 00212 error ('diffusive numerical flux unknown'); 00213 end; 00214 00215 % vim: set sw=2 et: 00216 %| \docupdate
1.7.4