rbmatlab 0.10.01
discfunc/fv/fv_num_diff_flux.m
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 
 All Classes Namespaces Files Functions Variables