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 %diff.K = 2*(difftmp.K + diffnei.K) ./ (difftmp.K + diffnei.K);
115 diff.K = mymean([difftmp.K, diffnei.K], 2);
116 diff.epsilon = mymean([difftmp.epsilon, diffnei.epsilon]);
118 diff = model.diffusivity_ptr([grid.ESX(:), grid.ESY(:)],[],model);
120 % exact diffusivity on dirichlet edges
121 if (~isempty(dir_NB_ind)) & (model.decomp_mode == 0)
122 Xdir = grid.ECX(dir_NB_ind);
123 Ydir = grid.ECY(dir_NB_ind);
124 Udir = model.dirichlet_values_ptr([Xdir(:),Ydir(:)],model);
125 Kdir = model.diffusivity_ptr([Xdir(:),Ydir(:)],Udir,model);
126 diff.K(dir_NB_ind) = Kdir.K(:);
134 K = ones(size(grid.ESX))*diff.K;
136 K = reshape(diff.K,size(grid.ESX));
138 Ulaplace = model.laplacian_derivative_ptr([grid.CX(:),...
141 if length(Ulaplace) == 1
142 Ulaplace = ones(size(grid.CX)) * Ulaplace;
144 Ulaplace = repmat(Ulaplace,1,grid.nneigh);
145 if ~isempty(dir_NB_ind)
146 Udirlaplace = model.laplacian_derivative_ptr([Xdir,Ydir],...
152 val = zeros(size(grid.ESX));
153 val(real_or_dir_NB_ind) = K(real_or_dir_NB_ind).* ...
154 grid.EL(real_or_dir_NB_ind).* ...
155 [ Ulaplace(real_NB_ind); Udirlaplace ] .* ...
156 (([grid.DS(real_NB_ind);1.0*grid.DS(dir_NB_ind)]).^(-1));
157 Ti_inv = repmat(grid.Ainv(:),1,grid.nneigh);
161 L_I_diag = sparse(1:n,1:n, sum(val,2));
162 % off-diagonal values:
163 [i,dummy] = ind2sub(size(grid.NBI),real_NB_ind);
164 L_I_offdiag = sparse(i,grid.NBI(real_NB_ind), -val(real_NB_ind),n,n);
165 L_I_diff = L_I_diag + L_I_offdiag;
167 L_I_diff = L_I_diff(NU_ind, :);
169 elseif decomp_mode == 1
170 % exactly identical computation as above for all components,
171 % weighting as given by the diffusivity.
172 L_I_diff = cell(length(diff),1);
173 % temporary quantities required for all q:
174 Ti_inv = repmat(grid.Ainv(:),1,grid.nneigh);
175 [i,dummy] = ind2sub(size(grid.NBI),real_NB_ind);
176 for q = 1:length(diff)
177 K = reshape(diff{q}.K,size(grid.ESX));
179 val = zeros(size(grid.ESX));
180 val(real_or_dir_NB_ind) = K(real_or_dir_NB_ind).* ...
181 grid.EL(real_or_dir_NB_ind).* ...
182 (1.0*grid.DS(real_or_dir_NB_ind)).^(-1);
186 L_I_diag = sparse(1:n,1:n, sum(val,2));
187 % off-diagonal values:
188 L_I_offdiag = sparse(i,grid.NBI(real_NB_ind), -val(real_NB_ind),n,n);
189 L_I_diff{q} = L_I_diag + L_I_offdiag;
191 else % decomp_mode==2: coefficients
192 % simply forward the diffusivity sigmas
196 %%%%%%%% 2. dirichlet-offset-vector:
197 % (bdir_I_diff)_i = - 1/|T_i| sum_j Ndir(i) (-d |S_ij|/d_ij u_dir(c_ij,t+dt))
199 if ~isempty(dir_NB_ind)
200 % evaluate dirichlet values at edge midpoints at t+dt
201 % Xdir, Ydir, Udir, K(dir_NB_ind) already computed above
204 Kdir = K(dir_NB_ind); % diffusivity already computed above
205 val2 = zeros(size(grid.ESX));
206 val2(dir_NB_ind)= - grid.EL(dir_NB_ind).*...
207 Udirlaplace.*((1.0*grid.DS(dir_NB_ind)).^(-1)) ...
209 bdir_I_diff = - grid.Ainv(:).* sum(val2,2);
211 bdir_I_diff = zeros(grid.nelements,1);
213 elseif decomp_mode == 1
214 if ~isempty(dir_NB_ind)
215 % evaluate dirichlet values at edge midpoints at t+dt
216 Xdir = grid.ECX(dir_NB_ind);
217 Ydir = grid.ECY(dir_NB_ind);
218 Udir = model.dirichlet_values_ptr([Xdir(:),Ydir(:)],model);
220 % for each combination of Udir and diffusivity component
221 % perform identical computation as above
222 Q_Udir = length(Udir);
223 Q_diff = length(diff);
224 bdir_I_diff = cell(Q_Udir * Q_diff,1);
227 Kdir = diff{q2}.K(dir_NB_ind); % diffusivity already computed above
228 val2 = zeros(size(grid.ESX));
229 val2(dir_NB_ind)= ...
230 - grid.EL(dir_NB_ind).*(grid.DS(dir_NB_ind).^(-1)) ...
232 bdir_I_diff{(q1-1)*Q_diff+q2} = ...
233 - grid.Ainv(:).* sum(val2,2);
237 % still produce dummy components as the availability of dir
238 % boundary cannot be detected in online phase
240 tmodel.decomp_mode = 2;
241 Udir = tmodel.dirichlet_values_ptr([],tmodel);
242 %
for each combination of Udir and diffusivity component
243 % perform identical computation as above
244 Q_Udir = length(Udir);
245 Q_diff = length(diff);
246 bdir_I_diff = cell(Q_Udir * Q_diff,1);
247 bdir_I_diff(:) = {zeros(grid.nelements,1)};
249 else % decomp_mode==2 -> coefficient
250 Udir = model.dirichlet_values_ptr([],model);
252 %
for each combination of Udir and diffusivity component
253 % perform identical computation as above
254 Q_Udir = length(Udir);
255 Q_diff = length(diff);
256 bdir_I_diff = zeros(Q_Udir * Q_diff,1);
259 bdir_I_diff((q1-1)*Q_diff+q2) = diff(q2) * Udir(q1);
264 % the following cannot be detected in coefficients mode!!!
265 %
else % no dirichlet-boundary:
266 %
if decomp_mode == 0
267 % bdir_I_diff = zeros(n,1);
268 % elseif decomp_mode == 1
270 %
else % decomp_mode == 2 -> coefficient
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 [ L_I_diff , bdir_I_diff ] = fv_operators_diff_implicit_gradient(model, model_data, U, NU_ind)
computes diffusion contributions to finite volume time evolution matrices, or their Frechet derivati...
function num_flux_mat = fv_num_diff_flux_gradient(model, model_data, U, NU_ind)
computes a numerical diffusive flux for a diffusion problem