1 function [L_I_diff, bdir_I_diff] = fv_operators_diff_implicit_gradient_tensor(...
2 model,model_data,NU_ind)
3 %
function [L_I_diff, bdir_I_diff] = ...
4 % fv_operators_diff_implicit_gradient_tensor(model,model_data[,NU_ind])
6 %
function computing the implicit diffusion contribution to the time evolution
7 % matrices
for a finite volume time step L_I * Unew = L_E * U + b
8 %
this function is called by fv_operators_implicit_explicit.
10 % the *_implicit functions perform a dt increase in model
11 % themselves before evaluating data functions
13 % Result is a sparse matrix L_I_diff and an offset vector
14 % bdir_I_diff, the latter containing dirichlet value contributions
16 % as numerical flux simple gradient approximation is used
18 % Function supports affine decomposition, i.e. different operation modes
19 % guided by optional field decomp_mode in model. See also the
20 % contents.txt
for general explanation
22 % Bernard Haasdonk 13.7.2006
24 % determine affine_decomposition_mode as integer
26 decomp_mode = model.decomp_mode;
30 model.t=model.t+model.dt;
32 if decomp_mode == 2 % coefficients
33 % simply forward the diffusivity sigmas
37 [tmpgrad,bdir] = gradient_approx_matrix(model, [], [], edge);
38 diff_k = model.diffusivity_ptr([], model);
39 L_I_temp = kron(tmpgrad, diff_k);
40 b_I_temp = kron(bdir, diff_k);
41 L_I_diff = [ L_I_diff, L_I_temp ];
42 bdir_I_diff = [ bdir_I_diff, b_I_temp ];
46 if ~isempty(model_data)
47 grid = model_data.grid;
52 if nargin < 3 || isempty(NU_ind)
53 NU_ind = 1:grid.nelements;
58 nu_ind_length = length(NU_ind);
60 % determine index sets of boundary types
61 real_NB_ind = find(grid.NBI>0);
62 % NBIind = grid.NBI(real_NB_ind);
63 % INBind = grid.INB(real_NB_ind);
64 % NB_real_NB_ind = sub2ind(size(grid.NBI),NBIind, INBind);
65 dir_NB_ind =find(grid.NBI == -1);
66 % real_or_dir_NB_ind = [real_NB_ind(:); dir_NB_ind(:)];
69 disp(['found ',num2str(length(real_NB_ind)),' non-boundary edges.'])
70 disp(['found ',num2str(length(dir_NB_ind)),' dirichlet-boundary edges.'])
73 if ~isequal(model.gridtype, '
rectgrid')
74 error(['gradient_tensor is not implemented for specified gridtype ', ...
80 if decomp_mode == 0 % complete mode
81 tmp_flux_mat = sparse(nu_ind_length, n);
82 bdir_I_diff = zeros(nu_ind_length, 1);
84 [tmpgrad,bdir] = gradient_approx_matrix(model, model_data, NU_ind, edge);
85 diff_k = model.diffusivity_ptr([grid.ECX(NU_ind,edge),grid.ECY(NU_ind,edge)], [], model);
87 model.diffusivity_tensor_ptr([grid.ECX(NU_ind,edge), grid.ECY(NU_ind,edge)], ...
90 % if nu_ind_set && model.debug
91 % disp(['any wrong: ', num2str(any(bdir2(reshape([2*NU_ind-1,2*NU_ind]',2*length(NU_ind),1))-bdir))]);
93 % if any(bdir2(reshape([2*NU_ind-1,2*NU_ind]',2*length(NU_ind),1))-bdir)
94 % [bdir, bdir2(reshape([2*NU_ind-1,2*NU_ind]',2*length(NU_ind),1))]
99 % this works only for scalar diffusivity -> use only first value of
100 % diffusivity vector (assumed to be homogeneous)
102 if any(repmat(diff_k.K(1),length(diff_k.K),1) ~= diff_k.K)
103 error(['Error: model.diffusivity_ptr does not return a homogeneous vector!\n',...
104 'This is invalid inside fv_operators_diff_implicit_gradient_tensor.']);
107 tmp1 = diff_k.K(1) * diff.K;
109 helper = sparse([1:nu_ind_length,1:nu_ind_length], ...
110 [2*(1:nu_ind_length)-1, 2*(1:nu_ind_length)], ...
111 reshape( [grid.NX(NU_ind,edge), grid.NY(NU_ind,edge)], ...
112 1, 2*nu_ind_length ) );
114 tmp2 = helper * tmp1;
116 ELL = spdiags(grid.EL(NU_ind,edge).*grid.Ainv(NU_ind,1),0,nu_ind_length,nu_ind_length);
117 tmp_flux_mat = tmp_flux_mat + ELL * tmp2 * tmpgrad;
118 bdir_I_diff = bdir_I_diff - tmp2 * bdir .* grid.EL(NU_ind,edge).*grid.Ainv(NU_ind,1);
120 L_I_diff = - tmp_flux_mat;
121 elseif decomp_mode == 1 % (components mode)
122 L_I_diff = cell(0,1);
123 bdir_I_diff = cell(0,1);
125 model.decomp_mode = 0;
126 diff = model.diffusivity_tensor_ptr([grid.ECX(NU_ind,edge), ...
127 grid.ECY(NU_ind,edge)],[],model, 3);
129 model.decomp_mode = 1;
130 [tmpgrad,bdir] = gradient_approx_matrix(model, model_data, NU_ind, edge);
131 diff_k = model.diffusivity_ptr([grid.ECX(NU_ind,edge),grid.ECY(NU_ind,edge)], [], model);
133 L_I_temp = cell(length(diff_k) * length(tmpgrad), 1);
134 b_I_temp = cell(length(diff_k) * length(bdir), 1);
136 helper = sparse([1:nu_ind_length,1:nu_ind_length], ...
137 [2*(1:nu_ind_length)-1, 2*(1:nu_ind_length)], ...
138 reshape( [grid.NX(NU_ind,edge), grid.NY(NU_ind,edge)], ...
139 1, 2*nu_ind_length ) );
141 for q=1:length(diff_k)
142 tmp1 = spdiags(repmat(diff_k{q}.K,2,1),0,size(diff.K,1),size(diff.K,2)) * diff.K;
143 tmp2 = helper * tmp1;
144 for r=1:length(tmpgrad)
145 % t = diag(grid.EL(:,edge)) * tmp2 * tmpgrad{r};
146 ELL = spdiags(grid.EL(NU_ind,edge).*grid.Ainv(NU_ind,1),0,nu_ind_length,nu_ind_length);
147 L_I_temp{ (q-1)*length(tmpgrad) + r } = ELL * tmp2 * tmpgrad{r};
150 b_I_temp{ (q-1)*length(bdir) + r } = tmp2 * bdir{r} .* grid.EL(NU_ind,edge).*grid.Ainv(NU_ind,1);
153 L_I_diff = [ L_I_diff; L_I_temp ];
154 bdir_I_diff = [ bdir_I_diff; b_I_temp ];
157 error([
'decomp_mode number ', model.decomp_mode,
' is unknown.']);
function r = verbose(level, message, messageId)
This function displays messages depending on a message-id and/or a level. Aditionally you can set/res...
A cartesian rectangular grid in two dimensions with axis parallel elements.