rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
SaturationSpace.m
1 classdef SaturationSpace < ILocalizedOperator
2 
3  properties (Constant)
4  id = 'L_saturation';
5 
6  ret_vars = {'saturation'};
7  arg_vars = {'saturation', 'velocity'};
8  arg_vars_short = {'S', 'U'};
9  end
10 
11  methods
12  function [INC, INCoff, J] = apply(this, model, model_data, sim_data, NU_ind)
13  %function INC = apply(this, model, model_data, sim_data, NU_ind)
14 
15  grid = model_data.grid;
16 
17  S = sim_data.S;
18  U = sim_data.U;
19 
20  if nargin <= 4 || isempty(NU_ind)
21  NU_ind = (1:length(S));
22  end
23 
24  if ~isfield(sim_data, 'm')
25  sim_data.m = length(S) + length(U);
26  end
27 
28  model.diffusivity_ptr = @(glob, U, model) model.two_phase.phi(glob, U, model);
29  model.diffusivity_derivative_ptr = @(glob, U, model) model.two_phase.phi_derivative(glob, U, model);
30  model.laplacian_ptr = @(glob, U, descr) U;
31  model.laplacian_derivative_ptr = @(glob, U, descr) ones(length(U),1);
32 
33  num_diff_flux_s = fv_num_diff_flux_gradient(model, model_data, S);
34 
35  num_conv_flux_s = fv_num_conv_flux_waterflow_upwind(model, model_data, S, U);
36 
37  % homogeneous neumann boundaries...
38  num_conv_flux_s.G(isnan(num_conv_flux_s.G)) = 0;
39 
40  if model.debug > 0
41  % find maximum index:
42  [maxval, maxi] = max(S);
43 
44  % disp(['maximum value: ', num2str(maxval), ' maximum cell index: ', num2str(maxi)]);
45  diff_max = num_diff_flux_s.G(maxi, :);
46  if any(diff_max < 0);
47  disp('all values need to be positive:')
48  disp(num2str(num_diff_flux_s.G(maxi, :)));
49  keyboard;
50  end
51  % ELmax = grid.EL(maxi, :);
52  Umax = U(model_data.gEI(maxi,:))'.*(grid.NX(maxi,:) + grid.NY(maxi,:));
53  conv_max = num_conv_flux_s.G(maxi, :);
54  Uconv_neg = zeros(size(num_conv_flux_s.G(maxi,:)));
55  Uconv_pos = zeros(size(num_conv_flux_s.G(maxi,:)));
56  Uconv_neg(Umax < 0) = conv_max(Umax < 0);
57  fUk = model.two_phase.waterflow([], S(maxi), model);
58  Uconv_pos(Umax < 0) = - Umax(Umax < 0) .* fUk;
59  if any(Uconv_pos + Uconv_neg < 0)
60  disp('all values need to be positive:')
61  disp(num2str(Uconv_pos + Uconv_neg));
62  keyboard;
63  end
64  cmax = model.two_phase.injection_concentration(model);
65  source_contri = (fUk - cmax) * S_upper(maxi);
66  if fUk > cmax
67  dodisp = source_contri < 0;
68  negpos = 'positive';
69  else
70  dodisp = source_contri > 0;
71  negpos = 'negative';
72  end
73  if dodisp
74  disp(['source contribution should be ', negpos, ': ', num2str(source_contri)]);
75  keyboard;
76  end
77 
78  %sink_contri_196 = (S(196) - model.two_phase.waterflow([], S(196), model)) * S_lower(196);
79  % disp(['sink at entity 196 = ', num2str(sink_contri_196)]);
80 
81 
82  if sum(Uconv_pos + Uconv_neg) + source_contri ~= sum(conv_max) - cmax * S_upper(maxi)
83  % disp('convective flux differs!');
84  % keyboard;
85  end
86 
87  % disp(['f(S_k) = ', num2str(fUk), ' c = ', num2str(cmax)]);
88  end
89 
90  INC = grid.Ainv(NU_ind, :) .* ...
91  ( sum(num_diff_flux_s.G(NU_ind,:), 2) ...
92  + sum(num_conv_flux_s.G(NU_ind,:), 2) ...
93  - model.two_phase.injection_concentration(model) .* model_data.opdata.S_upper ...
94  + S(NU_ind) .* model_data.opdata.S_lower );
95 
96  INCoff = [];
97 
98  if nargout > 2
99 
100  s_diff_s = fv_frechet_operators_diff_implicit_gradient3(model, model_data, S, NU_ind);
101  s_conv_s_u = fv_frechet_operators_conv_flux_waterflow_upwind(model, model_data, S, U, NU_ind);
102 
103  n = length(NU_ind);
104  UN_ind = zeros(length(S),1);
105  UN_ind(NU_ind) = 1:length(NU_ind);
106  if ~isfield(sim_data, 'Uoff')
107  sim_data.Uoff = length(S);
108  end
109  m = sim_data.m;
110 
111  sp11 = grid.Ainv(1).*sparse(UN_ind(s_diff_s.si), s_diff_s.sj, s_diff_s.svals, n, m);
112  sp121 = sparse(UN_ind(s_conv_s_u.si), s_conv_s_u.sj, s_conv_s_u.svals, n, m);
113  sp122 = sparse(UN_ind(s_conv_s_u.ui), s_conv_s_u.uj+sim_data.Uoff, s_conv_s_u.uvals, n, m);
114  sp12 = grid.Ainv(1).*(sp121+sp122);
115 
116  sli = intersect(find(model_data.opdata.S_lower), NU_ind);
117  sp13 = sparse(UN_ind(sli), sli, model_data.opdata.S_lower(sli) .* grid.Ainv(sli), n, m);
118 
119  J = sp11 + sp12 + sp13;
120  end
121 
122  end
123 
124  function ret_size = ret_size(this, model_data, NU_ind)
125  if nargin == 2 || isempty(NU_ind)
126  ret_size = model_data.grid.nelements;
127  else
128  ret_size = length(NU_ind);
129  end
130  end
131 
132  function arg_size = arg_size(this, model_data)
133  arg_size = 2 * model_data.grid.nelements;
134  end
135 
136  function ipm = inner_product_matrix(this, model_data)
137  ipm = model_data.W;
138  end
139 
140  function [nmd, eind, eind_local] = compute_TM_global(this, model_data, TM)
141  eind = ILocalizedOperator.compute_TM_global_edge(model_data, TM);
142  grid = model_data.grid;
143  glob2loc = zeros(max(TM),1);
144  glob2loc(eind) = 1:length(eind);
145  eind_local = glob2loc(TM);
146 
147  if isa(grid,'rectgrid') || isa(grid,'triagrid') || isa(grid,'onedgrid')
148  nmd.grid_local_ext = gridpart(grid,eind);
149 
150  gle = nmd.grid_local_ext;
151  mask = zeros(size(gle.NBI));
152  mask(eind_local, :) = 1;
153  [elnb_i, elnb_j] = find(gle.NBI(eind_local, :) > 0);
154  elnb = sub2ind(size(mask), eind_local(elnb_i), elnb_j);
155  mask(sub2ind(size(mask), gle.NBI(elnb), gle.INB(elnb))) = 1;
156  gle.NBI(~mask) = -10;
157 
158 % eind_local_inv = setdiff(1:nmd.grid_local_ext.nelements, eind_local);
159 % [tmp_i, tmp_j] = find(nmd.grid_local_ext.NBI(eind_local_inv, :) < 0);
160 % nmd.grid_local_ext.NBI(sub2ind(size(nmd.grid_local_ext.NBI), eind_local_inv(tmp_i), tmp_j')) = -10;
161 
162  [nmd.gEI, nmd.gn_inner_edges, nmd.gn_boundary_edges] ...
163  = compute_edge_indices(nmd.grid_local_ext);
164  nmd.gn_edges = nmd.gn_inner_edges + nmd.gn_boundary_edges;
165  else
166  error('unsupported grid');
167  end
168 
169  nmd.TM_global_args{1} = eind;
170  vel_global = zeros(1, model_data.gn_edges);
171  vel_global(model_data.gEI(TM, :)) = 1;
172  nmd.TM_global_args{2} = find(vel_global);
173  end
174 
175  function opdata = fill_opdata(this, rmodel, detailed_data)
176  if isa(rmodel.M, 'DataTree.IdMapNode')
177  MM = get_by_description(rmodel.M, 'L_saturation');
178  else
179  MM = rmodel.M;
180  end
181  opdata.S_lower = detailed_data.model_data.opdata.S_lower(detailed_data.TM(1:MM));
182  opdata.S_upper = detailed_data.model_data.opdata.S_upper(detailed_data.TM(1:MM));
183  end
184 
185  function opdata = copy_extract_opdata(this, opdata_copy, rmodel, Mid)
186  MM = get_by_description(rmodel.M, Mid);
187  opdata.S_lower = opdata_copy.S_lower(1:MM);
188  opdata.S_upper = opdata_copy.S_upper(1:MM);
189  end
190 
191 
192  end
193 end
Interface for a localized operator that fulfills the so-called -independent DOF dependence.
function [ gEI , in_edges , b_edges , i_ints_bigger , b_ints ] = compute_edge_indices(gridbase grid)
edge index matrix. This matrix maps each edge specified by the tuple (element_id, local_edge_id) to a...
function num_flux_mat = fv_num_diff_flux_gradient(model, model_data, U, NU_ind)
computes a numerical diffusive flux for a diffusion problem
function spm = fv_frechet_operators_conv_flux_waterflow_upwind(model, model_data, S, U, NU_ind)
computes a jacobian of implicit non-linear convective contributions to time evolution matrices at a p...
A triangular conforming grid in two dimensions.
Definition: triagrid.m:17
A cartesian rectangular grid in two dimensions with axis parallel elements.
Definition: rectgrid.m:17
function spm = fv_frechet_operators_diff_implicit_gradient3(model, model_data, U, NU_ind)
computes a jacobian of implicit non-linear diffusion contributions to time evolution matrices at a po...
a one dimensional grid implementation
Definition: onedgrid.m:17