3 % Function computing a numerical convective Engquist-Osher
6 % Engquist-Osher-Flux in 2D:
7 % ``g_{jl}(u,v) = |e_{jl}| \cdot (c^+_{jl}(u) + c^-_{jl}(v))``
9 % ``c^+_{jl}(u) = c_{jl}(0) + \int_0^u \max(c_{jl}
'(s),0) ds``
10 % ``c^-_{jl}(u) = \int_0^u \min(c_{jl}'(s),0) ds``
11 % ``c_{jl}(u) = f(u) \cdot n_{jl}``
14 % -# `f
'(u)\cdot n` does not change sign on `[0,u]` and
18 % ``c^+_{jl}(u) = \left\{\begin{array}{rl}
19 % f(u)\cdot n_{jl} & \mbox{if }f'(u)\cdot n_{jl} > 0 \\
20 % 0 & \mbox{otherwise}
21 % \end{array}\right.``
22 % ``c^-_{jl}(v) = \left\{\begin{array}{rl}
23 % f(v)\cdot n_{jl} & \mbox{
if }f
'(v)\cdot n_{jl} < 0 \\
24 % 0 & \mbox{otherwise}.
25 % \end{array}\right.``
27 % Dirichlet-boundary treatment is performed, but
28 % Neumann-values are set to 'nan
'. They must be performed by
29 % the calling function.
32 % Lg: lipschitz constant satisfying
33 % ``|g_{ij}(w,v) - g_{ij}(w',v
')| \leq Lg |S_{ij}| ( |w'-w| + |v
'-v| ).``
34 % G: the matrix of numerical flux values across the edges.
35 % boundary treatment is performed as follows:
36 % - in dirichlet-boundary points, the
37 % neighbour-values are simply set to this value and
38 % the flux is computed.
39 % - Neumann-treatment is not performed here
42 % We assume for the convective flux function:
43 % -# `f'(u)\cdot n` does not change sign on interval `(u,0)`
46 % Additionally, a velocity
function must be available in order to
47 % compute the derivative of the convection term.
50 % Bernard Haasdonk 10.4.2006
52 grid = model_data.grid;
54 if ~isempty(model.flux_quad_degree)
55 model.flux_quad_degree = 1;
59 num_flux.G = nan* ones(size(grid.NBI));
61 % determine index sets of boundary types
62 real_NB_ind = find(grid.NBI>0);
63 NBIind = grid.NBI(real_NB_ind);
64 INBind = grid.INB(real_NB_ind);
65 % NB_real_ind comprises comprises some kind of inverse cell-neighbour
66 % relation that leads back to the original cell from where we started
68 % [i,j]=ind2sub(size(grid.NBI),NB_real_NB_ind(sub2ind(size(grid.NBI),k,l)))
71 NB_real_NB_ind = sub2ind(size(grid.NBI),NBIind,INBind);
73 dir_NB_ind = find(grid.NBI == -1);
75 % matrix with the neighbouring function values
76 % UNB = nan * ones(size(grid.NBI));
77 % UNB(real_NB_ind) = U(grid.NBI(real_NB_ind));
78 UU = repmat(U,1,size(grid.NBI,2));
80 %%%%%%%%%%%%%%%%%%% convective numerical flux: Engquist Osher %%%%%%%%%%%%%%
82 if model.flux_linear && model.divclean_mode>0
83 error('divergence cleaning not implemented for engquist-osher!')
86 % evaluate flux matrix
87 % FxNB and FyNB and UNB are computed, where possible:
88 % both are valid in real_NB_ind
90 % matrix evaluating the flux by quadratures over all edges
93 % matrix with flux values, the neighbour values U(j) inserted
94 % values must be reflected across all edges
95 % i.e. GNB(i,j) = flux.G(NBI(i,j),INB(i,j))
96 % take care of boundary-indices!!
97 FxNB = nan * ones([grid.nelements,grid.nneigh]);
98 FyNB = nan * ones([grid.nelements,grid.nneigh]);
99 %[i,j] = ind2sub(size(flux_mat.G),NB_real_NB_ind);
100 [i,j] = ind2sub([grid.nelements, grid.nneigh],NB_real_NB_ind);
101 Fx = reshape(flux_mat(1,:,:),size(FxNB));
102 Fy = reshape(flux_mat(2,:,:),size(FxNB));
103 FxNB(real_NB_ind) = Fx(NB_real_NB_ind);
104 FyNB(real_NB_ind) = Fy(NB_real_NB_ind);
107 % evaluate flux matrix derivative (average over edges)
108 flux_derivative_mat = fv_conv_flux_linearization_matrix(model,model_data,U);
109 % produced fields: Vx, Vy
111 % matrix with flux values, the neighbour values U(j) inserted
112 % values must be reflected across all edges
113 % i.e. GNB(i,j) = flux.G(NBI(i,j),INB(i,j))
114 % take care of boundary-indices!!
115 VxNB = nan * ones(size(flux_derivative_mat.Vx));
116 % [i.j] = ind2sub(size(flux_mat.G),real_NB_ind);
117 VxNB(real_NB_ind) = flux_derivative_mat.Vx(NB_real_NB_ind);
119 VyNB = nan * ones(size(flux_derivative_mat.Vy));
120 % [i.j] = ind2sub(size(flux_mat.G),real_NB_ind);
121 VyNB(real_NB_ind) = flux_derivative_mat.Vy(NB_real_NB_ind);
123 if ~isempty(dir_NB_ind>0)
124 % ordinary flux evaluation by quadratures
125 % Fdir = conv_flux(model, Udir, Xdir, Ydir);
126 Xdir = grid.ECX(dir_NB_ind);
127 Ydir = grid.ECY(dir_NB_ind);
128 Udir = model.dirichlet_values_ptr([Xdir,Ydir],model);
129 [elids, edgeids] = ind2sub(size(grid.VI),dir_NB_ind);
130 PP = edge_quad_points(grid,elids,edgeids,model.flux_quad_degree);
132 ff = model.conv_flux_ptr(PP,...
133 repmat(Udir(:),model.flux_quad_degree,1), ...
135 Fdir.Fx = edge_quad_eval_mean(grid,elids,edgeids,...
136 model.flux_quad_degree,ff(:,1));
137 Fdir.Fy = edge_quad_eval_mean(grid,elids,edgeids,...
138 model.flux_quad_degree,ff(:,2));
140 ff_lin = model.conv_flux_derivative_ptr(PP,...
141 repmat(Udir(:),model.flux_quad_degree, 1), ...
143 Fdir_derivative.Vx = edge_quad_eval_mean(grid,elids,edgeids,...
144 model.flux_quad_degree,...
146 Fdir_derivative.Vy = edge_quad_eval_mean(grid,elids,edgeids,...
147 model.flux_quad_degree,...
150 FxNB(dir_NB_ind) = Fdir.Fx(:);
151 FyNB(dir_NB_ind) = Fdir.Fy(:);
152 VxNB(dir_NB_ind) = Fdir_derivative.Vx(:);
153 VyNB(dir_NB_ind) = Fdir_derivative.Vy(:);
157 % the following nicely maintains nan in Neumann-boundary edges
158 c_jl_u_deri = (grid.NX.* flux_derivative_mat.Vx + ...
159 grid.NY.* flux_derivative_mat.Vy);
160 I_c_jl_u_deri_pos = find (c_jl_u_deri > 0);
161 I_c_jl_u_deri_nonpos = c_jl_u_deri <= 0;
163 c_jl_v_deri = (grid.NX.* VxNB + grid.NY.* VyNB);
164 I_c_jl_v_deri_neg = find(c_jl_v_deri < 0);
165 I_c_jl_v_deri_nonneg = c_jl_v_deri >= 0;
167 c_jl_u_plus = nan * ones(size(grid.NBI)); % matrix of Nans
168 c_jl_u_plus(I_c_jl_u_deri_pos) = ...
169 grid.NX(I_c_jl_u_deri_pos).* Fx(I_c_jl_u_deri_pos) + ...
170 grid.NY(I_c_jl_u_deri_pos).* Fy(I_c_jl_u_deri_pos);
171 c_jl_u_plus(I_c_jl_u_deri_nonpos) = 0;
173 c_jl_v_minus = nan * ones(size(grid.NBI));
174 c_jl_v_minus(I_c_jl_v_deri_neg) = ...
175 grid.NX(I_c_jl_v_deri_neg).* FxNB(I_c_jl_v_deri_neg) + ...
176 grid.NY(I_c_jl_v_deri_neg).* FyNB(I_c_jl_v_deri_neg);
177 c_jl_v_minus(I_c_jl_v_deri_nonneg) = 0;
179 % add both components for final flux in all inner edges
180 num_flux.G = grid.EL.*(c_jl_u_plus + c_jl_v_minus);
182 % Lipschitz konstant Lg
183 % |g_ij(w,v) - g_ij(w',v')| <= Lg |S_ij| ( |w'-w| + |v'-v| )
185 num_flux.Lg = 1/ lambda;
187 % if grid.nelements == 200
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...
function num_flux = fv_num_conv_flux_engquist_osher(model, model_data, U, NU_ind)
Function computing a numerical convective Engquist-Osher flux matrix.