2 model, model_data, U, NU_ind)
3 %
function [L_I_diff, bdir_I_diff] = ...
5 % computes diffusion contributions to finite volume time evolution matrices,
6 % <b> or their Frechet derivative </b>
8 % This
function computes a diffusion
operator `L_{\text{diff}}` and a
9 % corresponding offset vector `b_{\text{diff}}` that can be used by
10 % fv_operators_implicit_explicit() to build evolution matrices for a finite
12 % `L_I U^{k+1} = L_E U^k + b_E + b_I`.
14 % The analytical term inspiring
this operator looks like
15 % `` - \nabla \cdot \left(d(u) \nabla l(u) \right). ``
16 % Here, the functions `d(u)` and `l(u)` differ in the numerical
19 % The latter is evaluated in cell centers during flux computation, whereas
20 % the diffusion functional `d(u)` is evaluated on the cell edges by averaging
21 % the solutions value there.
25 % The implemented flux then can be written
for inner boundaries as
26 % `` g_{ij}(u,v) = d(\{u,v\}) \frac{l(v) - l(u)}{|d_{ij}|} |e_{ij}| ``
27 % and
for Dirichlet boundaries as
28 % `` g_{dir,ij}(u) = d(u_{dir}(x_{ij}))
29 % \frac{l(u_{dir}(x_{ij})) - u}{|d_{ij}|} |e_{ij}|, ``
30 % where `\{u,v\}` refers to the average of `u` and `v`.
32 % \note that
this implementation only works
for trivial functions `l =
id`,
33 % because otherwise the
operator would became non-linear in the space
36 % If, however, `l(u)` is non-trivial, the flux arguments are simply
37 % <b>scaled</b> by `l
'(u)` giving rise to the Frechet derivative
38 % `D L_I|_{U}` that can be used in a Newton scheme. The offset vector
39 % 'bdir_I_diff
' can then be ignored, of course!
41 % required fields of model:
42 % diffusivity_ptr : The diffusivity function `d(u)`
43 % laplacian_derivative_ptr : The derivative `l'(u)`. See above
for
45 % dirichlet_values_ptr : The dirichlet
function `u_{\text{dir}}`
48 % L_I_diff : a sparse matrix with diffusion contributions to `L_I`.
49 % bdir_I_diff : and offset vector containing the Dirichlet value
50 % contributions of the diffusion parts.
53 % Bernard Haasdonk 13.7.2006
55 % determine affine_decomposition_mode as integer
56 decomp_mode = model.decomp_mode;
59 if ~isempty(model_data)
60 grid = model_data.grid;
69 % determine index sets of boundary types
70 real_NB_ind = find(grid.NBI>0);
71 %NBIind = grid.NBI(real_NB_ind);
72 %INBind = grid.INB(real_NB_ind);
73 % NB_real_NB_ind = sub2ind(size(grid.NBI),NBIind, INBind);
74 dir_NB_ind =find(grid.NBI == -1);
75 real_or_dir_NB_ind = [real_NB_ind(:); dir_NB_ind(:)];
78 disp(['found ',num2str(length(real_NB_ind)),' non-boundary edges.'])
79 disp(['found ',num2str(length(dir_NB_ind)),' dirichlet-boundary edges.'])
83 % currently assuming full implicit discretization of diffusivity
85 %%%%%%%% 1. implicit matrix:
87 % (L_I_diff)il = 1/|T_i| sum_j (NB(i) cup NB_dir(i))
88 % diff*|S_ij|/d_ij if l=i
89 % -diff |S_il|/d_il if l is NB(i)
91 % evaluate all edge midpoint diffusivities at time t+dt:
95 diff = model.diffusivity_ptr([],[],model);
98 tmpU = repmat(U, 1, grid.nneigh);
100 real_nb_ind = grid.NBI > 0;
101 neiU(real_nb_ind) = U(grid.NBI(real_nb_ind));
103 %edgeU = 0.5 * (tmpU + neiU);
104 %edgeU = sqrt(tmpU.*neiU);
105 %edgeU = min(tmpU,neiU);
106 %edgeU = 2*(1./tmpU + 1./neiU).^(-1);
107 %diff = model.diffusivity_ptr([grid.ESX(:), grid.ESY(:)],edgeU(:), model);
108 difftmp = model.diffusivity_ptr([grid.ESX(:),grid.ESY(:)],tmpU(:),model);
109 diffnei = model.diffusivity_ptr([grid.ESX(:),grid.ESY(:)],neiU(:),model);
111 if ~isfield(model, 'mean_ptr')
112 model.mean_ptr = @mean;
114 mymean = model.mean_ptr;
115 %diff.K = 2*(difftmp.K + diffnei.K) ./ (difftmp.K + diffnei.K);
117 diff.K = mymean([difftmp.K, diffnei.K], 2);
118 diff.epsilon = mymean([difftmp.epsilon, diffnei.epsilon]);
120 diff = model.diffusivity_ptr([grid.ESX(:), grid.ESY(:)],[],model);
122 % exact diffusivity on dirichlet edges
123 if (~isempty(dir_NB_ind)) & (model.decomp_mode == 0)
124 Xdir = grid.ECX(dir_NB_ind);
125 Ydir = grid.ECY(dir_NB_ind);
126 Udir = model.dirichlet_values_ptr([Xdir(:),Ydir(:)],model);
127 Kdir = model.diffusivity_ptr([Xdir(:),Ydir(:)],Udir,model);
128 diff.K(dir_NB_ind) = Kdir.K(:);
135 K = ones(size(grid.ESX))*diff.K;
137 K = reshape(diff.K,size(grid.ESX));
139 Ulaplace = model.laplacian_derivative_ptr([grid.CX(:),...
142 if length(Ulaplace) == 1
143 Ulaplace = ones(size(grid.CX)) * Ulaplace;
145 Ulaplace = repmat(Ulaplace,1,grid.nneigh);
146 if ~isempty(dir_NB_ind)
147 Udirlaplace = model.laplacian_derivative_ptr([Xdir,Ydir],...
153 val = zeros(size(grid.ESX));
154 val(real_or_dir_NB_ind) = K(real_or_dir_NB_ind).* ...
155 grid.EL(real_or_dir_NB_ind).* ...
156 [ Ulaplace(real_NB_ind); Udirlaplace ] .* ...
157 (([grid.DS(real_NB_ind);1.0*grid.DS(dir_NB_ind)]).^(-1));
158 % Ti_inv = repmat(grid.Ainv(:),1,grid.nneigh);
159 % val = val .* Ti_inv;
162 %L_I_diag = sparse(1:n,1:n, sum(val,2));
163 % off-diagonal values:
164 [i,dummy] = ind2sub(size(grid.NBI),real_NB_ind);
166 %L_I_offdiag = sparse(i,grid.NBI(real_NB_ind), -val(real_NB_ind),n,n);
170 spm.sj = [1:n, grid.NBI(real_NB_ind)'];
171 spm.svals = [sum(val,2)', -val(real_NB_ind(:)')];
173 if ~isempty(dir_NB_ind)
174 error('Dirichlet values not yet supported');
175 % evaluate dirichlet values at edge midpoints at t+dt
176 % Xdir, Ydir, Udir, K(dir_NB_ind) already computed above
178 Kdir = K(dir_NB_ind); % diffusivity already computed above
179 val2 = zeros(size(grid.ESX));
180 val2(dir_NB_ind)= - grid.EL(dir_NB_ind).*...
181 Udirlaplace.*((1.0*grid.DS(dir_NB_ind)).^(-1)) ...
183 % bdir_I_diff = - grid.Ainv(:).* sum(val2,2);
184 bdir_I_diff = - sum(val2,2);
186 bdir_I_diff = zeros(grid.nelements,1);
function r = verbose(level, message, messageId)
This function displays messages depending on a message-id and/or a level. Aditionally you can set/res...
function num_flux_mat = fv_num_diff_flux_gradient(model, model_data, U, NU_ind)
computes a numerical diffusive flux for a diffusion problem
function spm = fv_operators_diff_implicit_gradient2(model, model_data, U, NU_ind)
computes diffusion contributions to finite volume time evolution matrices, or their Frechet derivati...