3 % computes a numerical diffusive flux
for a diffusion problem including a tensor
5 % This
function computes a numerical diffusive flux matrix
for a diffusion
6 % problem. Dirichlet boundary treatment is performed, but neuman values are
set
7 % to
'NaN'. These must be handled by the calling
function.
9 % For discretization of a
'gradient_tensor' the parameter NU_ind is
10 % necessary,
if the gradient shall only be approximated on the local
11 % grid coordinates given by NU_ind.
13 % The analytical term inspiring
this flux looks like
14 % `` - \nabla \cdot \left( d(x) K(x,u) \nabla u \right),``
15 % with a function `d: R \to R` and a tensor `K: R \times R \to \text{Lin}(R^2, R^2)`.
17 % The implemented flux then can be written
for inner boundaries as
18 % ``g_{ij}(u,v) = d(x_{ij}) \tilde{K}(x,u,v)
19 % \tilde{\nabla}(u,v) |e_{ij}|``
20 % and
for Dirichlet boundaries as
21 % ``g_{dir,ij}(u) = d(x_{ij}) \tilde{K}_{dir}(x,u) \tilde{\nabla}(u) |e_{ij}|``
22 % where the discretizations `\tilde{K} and \tilde{\nabla}` of `K`
23 % respectively `\nabla` are given by the
function pointer
24 %
'model.diffusivity_tensor_ptr' respectively the
function gradient_approx().
25 % Note, that the latter is only available
for rectangular grids.
27 % required fields of model:
28 % diffusivity_ptr :
function pointer to diffusivity
function `d`
29 % diffusivity_tensor_ptr :
function pointer to a tensor implementation
for `K`
31 % generated fields of num_flux:
32 % epsilon: diffusion coefficient bound
33 % G: the matrix of numerical flux values across the edges.
34 % boundary treatment is performed as follows:
35 % in dirichlet-boundary edges, the neighbour-values are simply set
36 % to this value and the flux is computed.
38 % if grid is empty, it is generated
40 % Bernard Haasdonk 10.4.2006
42 grid = model_data.grid;
45 NU_ind = 1:grid.nelements;
48 %nu_ind_length = length(NU_ind);
52 num_flux.G = zeros(size(grid.NBI));
54 % determine index sets of boundary types
55 real_NB_ind = find(grid.NBI>0);
56 dir_NB_ind =find(grid.NBI == -1);
57 neu_NB_ind =find(grid.NBI == -2);
60 disp(['found ',num2str(length(real_NB_ind)),' non-boundary edges.'])
61 disp(['found ',num2str(length(dir_NB_ind)),' dirichlet-boundary edges.'])
62 disp(['found ',num2str(length(neu_NB_ind)),' neumann-boundary edges.'])
65 % get values in centers of the cells adjacent to the edge an the edges
66 % corner points. The corner values are computed by a 'weighted' average
67 % over the four adjacent cells. Then do an lsq approximation of the
68 % face the four points lie on. QUESTION: How can this be done in 3d and
70 if model.debug && ~isequal(model.gridtype, '
rectgrid')
71 error('gradient_tensor only implemented for rectangular grids');
74 G_with_nans = zeros(size(num_flux.G));
77 diff = model.diffusivity_tensor_ptr([grid.ECX(NU_ind,edge), ...
78 grid.ECY(NU_ind,edge)], ...
81 diff_k = model.diffusivity_ptr([grid.ECX(NU_ind,edge),...
82 grid.ECY(NU_ind,edge)], [], model);
84 % construct the diffusivity matrix D for current edge
85 %[tmpgrad,bdir] = gradient_approx_matrix(model,model_data,...
87 [tmpgrad] = gradient_approx(model,model_data,U,NU_ind,edge);
89 % tmp2 stores the matrix vector product of 'diffusion tensor x
91 vlen = size(tmpgrad,1);
92 tmpgrad = reshape(tmpgrad',2*vlen,1);
94 % compute on each intersection e = e_{i,edge} the diffusion tensor
95 % D_e = d_e * [ T_{e11}, T_{e12};
96 % T_{e21}, T_{e22} ] ...
97 tmp1 = spdiags(repmat(diff_k.K,2,1),0,size(diff.K,1),size(diff.K,2)) * diff.K;
98 % ... and multiply it with approximated gradient over the intersection
99 % g_e \circ \nabla U | _e:
102 % tmp2 = [ h_{e_{1,edge}}; h_{e_{2,edge}}; ... ; h_{e_{H,edge}} ].
103 tmp2 = tmp1 * tmpgrad;
105 %
if edge == 2 || edge == 4
106 % quiver(grid.ECX(:,edge),grid.ECY(:,edge), tmpgrad(:,1), tmpgrad(:,2));
108 % quiver(grid.ECX(:,edge),grid.ECY(:,edge), tmp2(:,1), tmp2(:,2));
113 tmp2 = reshape(tmp2, 2, vlen)
';
115 % M = length(NU_ind);
116 % offset = kron(M,NU_ind)-M;
117 % indices = repmat(offset',M,1)+repmat(NU_ind,1,M);
119 G_with_nans(NU_ind,edge) = sum(tmp2 .* [ grid.NX(NU_ind,edge),...
120 grid.NY(NU_ind,edge) ], 2);
122 G_with_nans = - G_with_nans .* grid.EL;
123 num_flux.G(real_NB_ind) = G_with_nans(real_NB_ind);
124 num_flux.G(dir_NB_ind) = G_with_nans(dir_NB_ind);
126 num_flux.epsilon = max(max(num_flux.G));