rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
fv_operators_diff_implicit_gradient.m
Go to the documentation of this file.
1 function [L_I_diff, bdir_I_diff] = fv_operators_diff_implicit_gradient(...
2  model, model_data, U, NU_ind)
3 %function [L_I_diff, bdir_I_diff] = ...
4 % fv_operators_diff_implicit_gradient(model,model_data[, U, NU_ind])
5 % computes diffusion contributions to finite volume time evolution matrices,
6 % <b> or their Frechet derivative </b>
7 %
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
11 % volume time step
12 % `L_I U^{k+1} = L_E U^k + b_E + b_I`.
13 %
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
17 % implementation.
18 %
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.
22 %
23 % See also: fv_num_diff_flux_gradient()
24 %
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`.
31 %
32 % \note that this implementation only works for trivial functions `l = id`,
33 % because otherwise the operator would became non-linear in the space
34 % variable.
35 %
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!
40 %
41 % required fields of model:
42 % diffusivity_ptr : The diffusivity function `d(u)`
43 % laplacian_derivative_ptr : The derivative `l'(u)`. See above for
44 % explanation.
45 % dirichlet_values_ptr : The dirichlet function `u_{\text{dir}}`
46 %
47 % Return values:
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.
51 %
52 
53 % Bernard Haasdonk 13.7.2006
54 
55 % determine affine_decomposition_mode as integer
56 decomp_mode = model.decomp_mode;
57 
58 grid = [];
59 if ~isempty(model_data)
60  grid = model_data.grid;
61 end
62 
63 if nargin < 4
64  NU_ind = [];
65 end
66 
67 if decomp_mode < 2
68  n = grid.nelements;
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(:)];
76 
77  if model.verbose >= 29
78  disp(['found ',num2str(length(real_NB_ind)),' non-boundary edges.'])
79  disp(['found ',num2str(length(dir_NB_ind)),' dirichlet-boundary edges.'])
80  end;
81 end;
82 
83 % currently assuming full implicit discretization of diffusivity
84 
85 %%%%%%%% 1. implicit matrix:
86 % has entries
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)
90 
91 % evaluate all edge midpoint diffusivities at time t+dt:
92 
93 
94 if decomp_mode == 2
95  diff = model.diffusivity_ptr([],[],model);
96 else
97  if nargin == 4
98  tmpU = repmat(U, 1, grid.nneigh);
99  neiU = tmpU;
100  real_nb_ind = grid.NBI > 0;
101  neiU(real_nb_ind) = U(grid.NBI(real_nb_ind));
102 
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);
110 
111  %diff.K = 2*(difftmp.K + diffnei.K) ./ (difftmp.K + diffnei.K);
112  %mymean = @harmmean;
113  %mymean = @geomean;
114  mymean = @mean;
115  diff.K = mymean([difftmp.K, diffnei.K], 2);
116  diff.epsilon = mymean([difftmp.epsilon, diffnei.epsilon]);
117  else
118  diff = model.diffusivity_ptr([grid.ESX(:), grid.ESY(:)],[],model);
119  end
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(:);
127  end
128 
129 end;
130 
131 
132 if decomp_mode == 0
133  if length(diff.K)==1
134  K = ones(size(grid.ESX))*diff.K;
135  else
136  K = reshape(diff.K,size(grid.ESX));
137  end
138  Ulaplace = model.laplacian_derivative_ptr([grid.CX(:),...
139  grid.CY(:)],...
140  U, model);
141  if length(Ulaplace) == 1
142  Ulaplace = ones(size(grid.CX)) * Ulaplace;
143  end
144  Ulaplace = repmat(Ulaplace,1,grid.nneigh);
145  if ~isempty(dir_NB_ind)
146  Udirlaplace = model.laplacian_derivative_ptr([Xdir,Ydir],...
147  Udir, model);
148  else
149  Udirlaplace = [];
150  end
151  % compute products
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);
158  val = val .* Ti_inv;
159 
160  % diagonal values:
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;
166  if ~isempty(NU_ind)
167  L_I_diff = L_I_diff(NU_ind, :);
168  end
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));
178  % compute products
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);
183  val = val .* Ti_inv;
184 
185  % diagonal values:
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;
190  end;
191 else % decomp_mode==2: coefficients
192  % simply forward the diffusivity sigmas
193  L_I_diff = diff;
194 end;
195 
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))
198 if decomp_mode ==0
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
202 
203 
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)) ...
208  .* Kdir .*Udir;
209  bdir_I_diff = - grid.Ainv(:).* sum(val2,2);
210  else
211  bdir_I_diff = zeros(grid.nelements,1);
212  end
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);
219 
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);
225  for q1 = 1:Q_Udir
226  for q2 = 1:Q_diff
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)) ...
231  .* Kdir .* Udir{q1};
232  bdir_I_diff{(q1-1)*Q_diff+q2} = ...
233  - grid.Ainv(:).* sum(val2,2);
234  end;
235  end;
236  else
237  % still produce dummy components as the availability of dir
238  % boundary cannot be detected in online phase
239  tmodel= model;
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)};
248  end;
249 else % decomp_mode==2 -> coefficient
250  Udir = model.dirichlet_values_ptr([],model);
251 
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);
257  for q1 = 1:Q_Udir
258  for q2 = 1:Q_diff
259  bdir_I_diff((q1-1)*Q_diff+q2) = diff(q2) * Udir(q1);
260  end;
261  end;
262 end;
263 
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
269 % bdir_I_diff = {};
270 % else % decomp_mode == 2 -> coefficient
271 % bdir_I_diff = [];
272 % end;
273 % end;
274 
function r = verbose(level, message, messageId)
This function displays messages depending on a message-id and/or a level. Aditionally you can set/res...
Definition: verbose.m:17
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