rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
fv_num_conv_flux.m
1 function num_flux = fv_num_conv_flux(model,model_data,U)
2 %function num_flux = fv_num_conv_flux(model,model_data,U)
3 %
4 % function computing a numerical convective flux
5 % matrix. Dirichlet-boundary treatment is performed, but Neuman-values
6 % are set to nan, must be performed by calling function. Currently implemented
7 % lax-friedrichs and engquist-osher.
8 %
9 % fields of num_flux:
10 % Lg: lipschitz constant satisfying
11 % |g_ij(w,v) - g_ij(w',v')| <= Lg |S_ij| ( |w'-w| + |v'-v| )
12 % G: the matrix of numerical flux values across the edges.
13 % boundary treatment is performed as follows:
14 % in dirichlet-boundary points, the neighbour-values are simply set
15 % to this value and the flux computed.
16 % Neuman-treatment is not performed here
17 %
18 % required fields of model:
19 % name_convective_num_flux : 'none', 'lax-friedrichs', 'engquist-osher'
20 %
21 % in case of lax-friedrichs, either as diffusivity the value of the
22 % flux_matrix is used or explicit setting of the value by
23 % model.lxf_lambda is possible.
24 %
25 % for engquist-osher, we assume for the convective flux function:
26 % 1. f'(u)*n does not change sign on interval(u,0)
27 % 2. f(0) = 0
28 % additionally, a conv_flux_derivative data-function must be available.
29 %
30 % plus additional fields required by dirichlet_values
31 %
32 % if grid is empty, it is generated
33 
34 % Bernard Haasdonk 10.4.2006
35 
36  grid = model_data.grid;
37 
38 % if ~isfield(model,'flux_quad_degree')
39 % model.flux_quad_degree = 1;
40 % end;
41 
42  num_flux = [];
43  num_flux.G = nan* ones(size(grid.NBI));
44 
45  % determine index sets of boundary types
46  real_NB_ind = find(grid.NBI>0);
47  NBIind = grid.NBI(real_NB_ind);
48  INBind = grid.INB(real_NB_ind);
49  % NB_real_ind comprises comprises some kind of inverse cell-neighbour
50  % relation that leads back to the original cell from where we started
51  % Falls
52  % [i,j]=ind2sub(size(grid.NBI),NB_real_NB_ind(sub2ind(size(grid.NBI),k,l)))
53  % dann ist
54  % grid.NBI(i,j) == k
55  NB_real_NB_ind = sub2ind(size(grid.NBI),NBIind,INBind);
56 
57  dir_NB_ind = find(grid.NBI == -1);
58 
59  % matrix with the neighbouring function values
60  % UNB = nan * ones(size(flux_mat.Fx));
61  UNB = nan * ones(size(grid.NBI));
62  UNB(real_NB_ind) = U(grid.NBI(real_NB_ind));
63  UU = repmat(U,1,size(grid.NBI,2));
64 
65  %%%%%%%%%%%%%%%%%%% convective numerical flux: Lax-Friedrichs %%%%%%%%%%%%%%
66  if isequal(model.name_convective_num_flux,'nonlinear-diffusion')
67  % g_jl(u,v) = |S_ij| K(grid.ESX,grid.ESY, u(ES))(psi(v)-psi(u))
68  % z.B. u(ES) = 0.5(u+v)
69 
70 
71  %%%%%%%%%%%%%%%%%%% convective numerical flux: Lax-Friedrichs %%%%%%%%%%%%%%
72  elseif isequal(model.name_convective_num_flux,'lax-friedrichs')
73  % Lax-Friedrichs-Flux in 2D:
74  % g_jl(u,v) = 1/2 * nu_jl (f(u,Sx,Sy) + f(v,Sx,Sy)) -
75  % |S_jl|/(2 lambda_jl) (v-u)
76  % or equivalently
77  % g_jl(u,v) = 1/2 |S_ij| * (n_jl * (f(u)+f(v)) - ...
78  % 1/(2 lambda_jl) (v-u))
79  % mit lambda_jl := dt / |m_j - m_l|
80 
81  % FxNB and FyNB and UNB are computed, where possible:
82  % both are valid in real_NB_ind
83 
84  % matrix evaluating the flux by quadratures over all edges
85  flux_mat = fv_conv_flux_matrix(model,model_data,U);
86 
87  % in case of divergence cleaning, the velocity field must be
88  % available!! This is obtianed by setting u to 1
89  if (model.divclean_mode>0)
90  Udummy = ones(size(U));
91  flux_mat_Uone = fv_conv_flux_matrix(model,model_data,Udummy);
92  end;
93 
94  % matrix with flux values, the neighbour values U(j) inserted
95  % values must be reflected across all edges
96  % i.e. GNB(i,j) = flux.G(NBI(i,j),INB(i,j))
97  % take care of boundary-indices!!
98  FxNB = nan * ones(size(flux_mat.Fx));
99  % [i.j] = ind2sub(size(flux_mat.G),real_NB_ind);
100  FxNB(real_NB_ind) = flux_mat.Fx(NB_real_NB_ind);
101 
102  FyNB = nan * ones(size(flux_mat.Fy));
103  % [i.j] = ind2sub(size(flux_mat.G),real_NB_ind);
104  FyNB(real_NB_ind) = flux_mat.Fy(NB_real_NB_ind);
105 
106  % L1 is the supremum in space of the derivative of the first component
107  % L2 is the supremum in space of the derivative of the second component
108  L1 = max(max(abs(flux_mat.Fx)));
109  L2 = max(max(abs(flux_mat.Fy)));
110 
111  % Lipschitz-constant of LxF Flux
112  num_flux.Lg = 1/(2*flux_mat.lambda) + 1/2 * norm([L1, L2]);
113  % an alternative formula without motivation:
114  % num_flux.Lg = max(max(grid.S)) * model.c * 0.25;
115 
116  % in the linear case the following worked:
117  % numflux_mat.G = 1/2 * grid.S .* ...
118  % (grid.Nx.* (flux_mat.Vx.*(OU + OUext(grid.NBI))) + ...
119  % grid.Ny.* (flux_mat.Vy.*(OU + OUext(grid.NBI)))) ...
120  % + 1/(2 * flux_mat.lambda) * grid.S .* (OU - OUext(grid.NBI));
121 
122  lambda = flux_mat.lambda;
123  if ~isempty(model.lxf_lambda)
124  lambda = model.lxf_lambda;
125  end;
126 
127  % in the general nonlinear case:
128  num_flux.G = 1/2 * grid.EL .* ...
129  (grid.NX.* (flux_mat.Fx + FxNB) + ...
130  grid.NY.* (flux_mat.Fy + FyNB)) ...
131  + 1/(2 * lambda) * grid.EL .* (UU - UNB);
132 
133  % Dirichlet boundary treatment
134  if ~isempty(dir_NB_ind>0)
135  % determine dirichlet-boundary values as required by convective
136  % and diffusive flux. Neumann determined at end
137  Xdir = grid.ECX(dir_NB_ind);
138  Ydir = grid.ECY(dir_NB_ind);
139  Udir = model.dirichlet_values_ptr([Xdir,Ydir],model);
140 
141  % if conv_flux_matrix has been divergence cleaned, no further
142  % flux evaluations may be performed!!
143  if ~isequal(model.divclean_mode,'none')
144  if model.verbose>9
145  disp('skipping boundary flux eval. due to divergence cleaning!!');
146  end;
147  % the following is unstable, if U reaches 0!!!!
148  % Fdir.Fx = flux_mat.Fx(dir_NB_ind)./UU(dir_NB_ind).*Udir;
149  % Fdir.Fy = flux_mat.Fy(dir_NB_ind)./UU(dir_NB_ind).*Udir;
150  % instead again evaluation of the whole matrix.
151  Fdir.Fx = flux_mat_Uone.Fx(dir_NB_ind).*Udir;
152  Fdir.Fy = flux_mat_Uone.Fy(dir_NB_ind).*Udir;
153 
154  else % ordinary flux evaluation by quadratures
155  % Fdir = conv_flux(model,Udir, Xdir, Ydir);
156  [elids, edgeids] = ind2sub(size(grid.VI),dir_NB_ind);
157  PP = edge_quad_points(grid,elids, edgeids, ...
158  model.flux_quad_degree);
159 
160  % the following is only relevant in case of use of a
161  % model.use_velocitymatrix_file and filecaching mode 2
162  if model.filecache_velocity_matrixfile_extract == 2;
163  model.velocity_matrixfile = ...
164  cache_velocity_matrixfile_extract(model,PP(1,:),PP(2,:),...
165  'dirichlet_bnd');
166  end;
167 
168  ff = conv_flux(model, repmat(Udir(:),model.flux_quad_degree,1), ...
169  PP(1,:), PP(2,:) );
170  Fdir.Fx = edge_quad_eval_mean(grid,elids,edgeids,...
171  model.flux_quad_degree,ff.Fx);
172  Fdir.Fy = edge_quad_eval_mean(grid,elids,edgeids,...
173  model.flux_quad_degree,ff.Fy);
174  end;
175 
176  % num_flux.G(dir_NB_ind) = grid.S(dir_NB_ind) .* ...
177  % (grid.Nx(dir_NB_ind) .* Fdir.Fx + ...
178  % grid.Ny(dir_NB_ind) .* Fdir.Fy);
179 
180  % better solution: Lxf with "ghost-cells"
181  num_flux.G(dir_NB_ind) = 1/2 * grid.EL(dir_NB_ind) .* ...
182  (grid.NX(dir_NB_ind).* (flux_mat.Fx(dir_NB_ind) + Fdir.Fx) + ...
183  grid.NY(dir_NB_ind).* (flux_mat.Fy(dir_NB_ind) + Fdir.Fy)) ...
184  + 1/(2 * lambda) * grid.EL(dir_NB_ind) .* ...
185  (UU(dir_NB_ind) - Udir);
186 
187  end; % of Dirichlet treatment
188 
189  %%%%%%%%%%%%%%%%%%% convective numerical flux: Engquist Osher %%%%%%%%%%%%%%
190  elseif isequal(model.name_convective_num_flux,'engquist-osher') ...
191  || isequal(model.name_convective_num_flux,'enquist-osher')
192 
193  % Engquist-Osher-Flux in 2D:
194  % g_jl(u,v) = |e_jl| * (c^+_jl(u) + c^-_jl(v))
195  % with
196  % c^+_jl(u) = c_jl(0) + int_0^u max(c_jl'(s),0) ds
197  % c^-_jl(u) = int_0^u min(c_jl'(s),0) ds
198  % c_jl(u) = f(u) * n_jl
199  %
200  % if we assume, that
201  % 1. f'(u)*n does not change sign on [0,u] and
202  % 2. f(0) = 0
203  % then
204  % this simplifies to
205  % c^+_jl(u) = / f(u)*n_jl if f'(u)*n_jl > 0
206  % \ 0 otherwise
207  % c^-_jl(v) = / f(v)*n_jl if f'(v)*n_jl < 0
208  % \ 0 otherwise
209 
210 
211  if model.divclean_mode>0
212  error('divergence cleaning not implemented for engquist-osher!')
213  end;
214 
215  % evaluate flux matrix
216  % FxNB and FyNB and UNB are computed, where possible:
217  % both are valid in real_NB_ind
218 
219  % matrix evaluating the flux by quadratures over all edges
220  [flux_mat, lambda] = fv_conv_flux_matrix(model,model_data,U);
221 
222  % matrix with flux values, the neighbour values U(j) inserted
223  % values must be reflected across all edges
224  % i.e. GNB(i,j) = flux.G(NBI(i,j),INB(i,j))
225  % take care of boundary-indices!!
226  FxNB = nan * ones([grid.nelements,grid.nneigh]);
227  FyNB = nan * ones([grid.nelements,grid.nneigh]);
228  %[i,j] = ind2sub(size(flux_mat.G),NB_real_NB_ind);
229  [i,j] = ind2sub([grid.nelements, grid.nneigh],NB_real_NB_ind);
230  Fx = reshape(flux_mat(1,:,:),size(FxNB));
231  Fy = reshape(flux_mat(2,:,:),size(FxNB));
232  FxNB(real_NB_ind) = Fx(NB_real_NB_ind);
233  FyNB(real_NB_ind) = Fy(NB_real_NB_ind);
234 
235 
236  % evaluate flux matrix derivative (average over edges)
237  flux_derivative_mat = fv_conv_flux_linearization_matrix(model,model_data,U);
238  % produced fields: Vx, Vy
239 
240  % matrix with flux values, the neighbour values U(j) inserted
241  % values must be reflected across all edges
242  % i.e. GNB(i,j) = flux.G(NBI(i,j),INB(i,j))
243  % take care of boundary-indices!!
244  VxNB = nan * ones(size(flux_derivative_mat.Vx));
245  % [i.j] = ind2sub(size(flux_mat.G),real_NB_ind);
246  VxNB(real_NB_ind) = flux_derivative_mat.Vx(NB_real_NB_ind);
247 
248  VyNB = nan * ones(size(flux_derivative_mat.Vy));
249  % [i.j] = ind2sub(size(flux_mat.G),real_NB_ind);
250  VyNB(real_NB_ind) = flux_derivative_mat.Vy(NB_real_NB_ind);
251 
252  if ~isempty(dir_NB_ind>0)
253  % ordinary flux evaluation by quadratures
254  % Fdir = conv_flux(model, Udir, Xdir, Ydir);
255  Xdir = grid.ECX(dir_NB_ind);
256  Ydir = grid.ECY(dir_NB_ind);
257  Udir = model.dirichlet_values_ptr([Xdir,Ydir],model);
258  [elids, edgeids] = ind2sub(size(grid.VI),dir_NB_ind);
259  PP = edge_quad_points(grid,elids, edgeids,model.flux_quad_degree);
260 
261  ff = conv_flux(model, repmat(Udir(:),model.flux_quad_degree,1), ...
262  PP(1,:), PP(2,:) );
263  Fdir.Fx = edge_quad_eval_mean(grid,elids,edgeids,...
264  model.flux_quad_degree,ff.Fx);
265  Fdir.Fy = edge_quad_eval_mean(grid,elids,edgeids,...
266  model.flux_quad_degree,ff.Fy);
267 
268  ff_lin = conv_flux_linearization(model, repmat(Udir(:),...
269  model.flux_quad_degree,...
270  1), ...
271  PP(1,:), PP(2,:) );
272  Fdir_derivative.Vx = edge_quad_eval_mean(grid,elids,edgeids,...
273  model.flux_quad_degree,...
274  ff_lin.Vx);
275  Fdir_derivative.Vy = edge_quad_eval_mean(grid,elids,edgeids,...
276  model.flux_quad_degree,...
277  ff_lin.Vy);
278 
279  FxNB(dir_NB_ind) = Fdir.Fx(:);
280  FyNB(dir_NB_ind) = Fdir.Fy(:);
281  VxNB(dir_NB_ind) = Fdir_derivative.Vx(:);
282  VyNB(dir_NB_ind) = Fdir_derivative.Vy(:);
283 
284  end;
285 
286  % the following nicely maintains nan in Neumann-boundary edges
287  c_jl_u_deri = (grid.NX.* flux_derivative_mat.Vx + ...
288  grid.NY.* flux_derivative_mat.Vy);
289  I_c_jl_u_deri_pos = find (c_jl_u_deri > 0);
290  I_c_jl_u_deri_nonpos = c_jl_u_deri <= 0;
291 
292  c_jl_v_deri = (grid.NX.* VxNB + grid.NY.* VyNB);
293  I_c_jl_v_deri_neg = find(c_jl_v_deri < 0);
294  I_c_jl_v_deri_nonneg = c_jl_v_deri >= 0;
295 
296  c_jl_u_plus = nan * ones(size(grid.NBI)); % matrix of Nans
297  c_jl_u_plus(I_c_jl_u_deri_pos) = ...
298  grid.NX(I_c_jl_u_deri_pos).* Fx(I_c_jl_u_deri_pos) + ...
299  grid.NY(I_c_jl_u_deri_pos).* Fy(I_c_jl_u_deri_pos);
300  c_jl_u_plus(I_c_jl_u_deri_nonpos) = 0;
301 
302  c_jl_v_minus = nan * ones(size(grid.NBI));
303  c_jl_v_minus(I_c_jl_v_deri_neg) = ...
304  grid.NX(I_c_jl_v_deri_neg).* FxNB(I_c_jl_v_deri_neg) + ...
305  grid.NY(I_c_jl_v_deri_neg).* FyNB(I_c_jl_v_deri_neg);
306  c_jl_v_minus(I_c_jl_v_deri_nonneg) = 0;
307 
308  % add both components for final flux in all inner edges
309  num_flux.G = grid.EL.*(c_jl_u_plus + c_jl_v_minus);
310 
311  % Lipschitz konstant Lg
312  % |g_ij(w,v) - g_ij(w',v')| <= Lg |S_ij| ( |w'-w| + |v'-v| )
313 
314  num_flux.Lg = 1/ lambda;
315 
316  %%%%%%%%%%%%%%%%%%% convective numerical flux: None %%%%%%%%%%%%%%
317  elseif isequal(model.name_convective_num_flux,'none')
318  % do nothing;
319  num_flux.Lg = 0;
320  else
321  error ('convective numerical flux unknown');
322  end;
323 
324 %keyboard;
325 %| \docupdate
function [ flux_mat , lambda ] = fv_conv_flux_matrix(model, model_data, U, conv_flux_ptr)
function computing the flux matrix of a convection problem. simply reformatting the grid data suitabl...