rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
CompositeFunctionSpace.m
1 classdef CompositeFunctionSpace < Fem.IFemInfo & DataTree.IdMapNode
2  %classdef CompositeFunctionSpace < Fem.IFemInfo & DataTree.IdMapNode
3  % Composite function space for composition of FE function spaces on
4  % same grid.
5 
6  properties (SetAccess = private, Dependent)
7 
8  % polynomial degree, possibly vector of dimrange > 1
9  pdeg;
10 
11  % dimension of range space
12  dimrange;
13 
14  % number of DOFs
15  ndofs;
16 
17  % number of DOFs per grid element
18  ndofs_per_element;
19 
20  % grid of type .gridbase
21  grid;
22 
23  % determinant of reference mapping
24  detDF;
25 
26  dofs_lcoord;
27  dofs_edges_llcoord;
28  l2_inner_product_matrix;
29  h10_inner_product_matrix;
30  end
31 
32  properties (SetAccess = private)
33 
34  % a cell array of length dimrange, i-th entry is a 1 x ndofs_per_element(dimrange=i) matrix
35  dof_ids_local;
36 
37  % number of grid cells
38  nelements;
39  end
40 
41  properties (Access = private, Hidden)
42 
43  % vectors of length size(this)
44  dim_offsets;
45  ldof_offsets;
46  gdof_offsets;
47  end
48 
49  methods
50 
51  function cfs = CompositeFunctionSpace(varargin)
52  % Constructor
53  %
54  % Parameters:
55  % varargin: either parameters for IdMapNode constructor or
56  % list of function spaces following id-strings: (df1, id1,
57  % df2, id2, ...)
58 
59  if iscell(varargin{1})
60  superclass_args = varargin;
61  else
62  superclass_args{1} = varargin(2:2:end);
63  superclass_args{2} = varargin(1:2:end-1);
64  end
65 
66  cfs = cfs@DataTree.IdMapNode(superclass_args{:});
67 
68  consistency_check(cfs);
69 
70  cfs.dim_offsets = zeros(length(cfs), 1);
71  cfs.ldof_offsets = zeros(length(cfs), 1);
72  cfs.gdof_offsets = zeros(length(cfs), 1);
73  for i = 2:length(cfs)
74  cfs.dim_offsets(i) = cfs.dim_offsets(i-1) + cfs.values{i-1}.dimrange;
75  cfs.ldof_offsets(i) = cfs.ldof_offsets(i-1) + cfs.values{i-1}.ndofs_per_element;
76  cfs.gdof_offsets(i) = cfs.gdof_offsets(i-1) + cfs.values{i-1}.ndofs;
77  end
78 
79  cfs.dof_ids_local = cellfun(...
80  @(fs, offset) cellfun(@(vec) vec+offset, fs.dof_ids_local(:), 'UniformOutput', false), ...
81  cfs.values(:), num2cell(cfs.ldof_offsets(:)), 'UniformOutput', false);
82 
83  cfs.dof_ids_local = cat(1, cfs.dof_ids_local{:});
84 
85  cfs.nelements = cfs.grid.nelements;
86  end
87 
88  function this = set(this, index, value)
89 
90  if index == (length(this)+1)
91  this.dim_offsets = [this.dim_offsets; this.dim_offsets(end) + value.dimrange];
92  this.ldof_offsets = [this.ldof_offsets; this.ldof_offsets(end) + value.ndofs_per_element];
93  this.gdof_offsets = [this.gdof_offsets; this.gdof_offsets(end) + value.ndofs];
94  elseif index > (length(this) + 1)
95  error('Index too large in set@CompositeFunctionSpace.');
96  end
97  this = set@DataTree.IdMapNode(this, index, value);
98  consistency_check(this);
99 
100  for i = 1:length(this) - index
101  this.dim_offsets(index+i) = this.dim_offsets(index+i-1) + cfs.values{index+i-1}.dimrange;
102  this.ldof_offsets(index+i) = this.ldof_offsets(index+i-1) + cfs.values{index+i-1}.ndofs_per_element;
103  this.gdof_offsets(index+i) = this.gdof_offsets(index+i-1) + cfs.values{index+i-1}.ndofs;
104  end
105  end
106 
107  function consistency_check(this)
108  % grids have to be identical
109  for i = 2:length(this)
110  if this.values{1}.grid ~= this.values{i}.grid;
111  error('Grids inconsistent in CompositeFunctionSpace.');
112  end
113  end
114  end
115 
116  function pdeg = get.pdeg(this)
117  % concatenate pdegs
118  pdeg = cellfun(@(fs)fs.pdeg(:)', this.values, 'UniformOutput', false);
119  pdeg = cat(2, pdeg{:});
120  end
121 
122  function dimrange = get.dimrange(this)
123  % sum of children dimensions
124  dimrange = this.dim_offsets(end) + this.values{end}.dimrange;
125  end
126 
127  function ndofs = get.ndofs(this)
128  % sum of ndofs of children
129  ndofs = this.gdof_offsets(end) + this.values{end}.ndofs;
130  end
131 
132  function ndofs_per_element = get.ndofs_per_element(this)
133  % sum of ndofs_per_element of children
134  ndofs_per_element = this.ldof_offsets(end) + this.values{end}.ndofs_per_element;
135  end
136 
137  function grid = get.grid(this)
138  dfs = get(this, 1);
139  while isa(dfs, 'DataTree.IdMapNode')
140  dfs = get(dfs, 1);
141  end
142  grid = dfs.grid;
143  end
144 
145  function detDF = get.detDF(this)
146  dfs = get(this, 1);
147  while isa(dfs, 'DataTree.IdMapNode')
148  dfs = get(dfs, 1);
149  end
150  detDF = dfs.detDF;
151  end
152 
153  function dofs_lcoord = get.dofs_lcoord(this)
154  dofs_lcoord = cellfun(@(fs) fs.dofs_lcoord, this.values, 'UniformOutput', false);
155  dofs_lcoord = cat(1, dofs_lcoord{:});
156  end
157 
158  function dofs_edges_llcoord = get.dofs_edges_llcoord(this)
159  dofs_edges_llcoord = cellfun(@(fs) fs.dofs_edges_llcoord, ...
160  this.values, 'UniformOutput', false);
161  dofs_edges_llcoord = cat(1, dofs_edges_llcoord{:});
162  end
163 
164  function l2_inner_product_matrix = get.l2_inner_product_matrix(this)
165  l2_inner_product_matrix = cellfun(@(fs) fs.l2_inner_product_matrix, ...
166  this.values, 'UniformOutput', false);
167  l2_inner_product_matrix = blkdiag(l2_inner_product_matrix{:});
168  end
169 
170  function h10_inner_product_matrix = get.h10_inner_product_matrix(this)
171  h10_inner_product_matrix = cellfun(@(fs) fs.h10_inner_product_matrix, ...
172  this.values, 'UniformOutput', false);
173  h10_inner_product_matrix = blkdiag(h10_inner_product_matrix{:});
174  end
175 
176  function res = evaluate_basis(this, lcoord)
177  % evaluation of all basis functions in local coordinate
178  res = [];
179  for i = 1:length(this)
180  res = blkdiag(res, evaluate_basis(this.values{i}, lcoord));
181  end
182  %res = cellfun(@(fs) evaluate_basis(fs, lcoord), this.values, 'UniformOutput', false);
183  %res = blkdiag(res{:});
184  end
185 
186  function res = evaluate_scalar_basis_derivative(this, lcoord, ncomp)
187  % evaluation of the gradient of a scalar basis in local coordinate
188  child_ind = find(this.dim_offsets < ncomp, 1, 'last');
189  res = evaluate_scalar_basis_derivative(this.values{child_ind}, ...
190  lcoord, ncomp - this.dim_offsets(child_ind));
191  end
192 
193  function res = evaluate_basis_function(this, lcoord, i)
194  % evaluation of i-th basis function in local coordinate
195  child_ind = find(this.ldof_offsets < i, 1, 'last');
196  res = zeros(this.dimrange, 1);
197  res(this.dim_offsets(child_ind) + (1:this.values{child_ind}.dimrange)) ...
198  = evaluate_basis_function(this.values{child_ind}, lcoord, i - this.ldof_offsets(child_ind));
199  end
200 
201  function res = evaluate_basis_function_derivative(this, lcoord, i)
202  % evaluation of the gradient of i-th basis function in local
203  % coordinate
204  child_ind = find(this.ldof_offsets < i, 1, 'last');
205  res = zeros(this.dimrange, 2); % R^2
206  res(this.dim_offsets(child_ind) + (1:this.values{child_ind}.dimrange), :) ...
207  = evaluate_basis_function_derivative(this.values{child_ind}, ...
208  lcoord, i - this.ldof_offsets(child_ind));
209  end
210 
211  function res = get_global_dof_index(this, varargin)
212  % returns entries of global-dof-map for several elements and several
213  % local dof ids
214  if nargin == 1
215  res = zeros(this.nelements, this.ndofs_per_element);
216  for i = 1:length(this)
217  res(:, this.ldof_offsets(i)+(1:this.values{i}.ndofs_per_element)) ...
218  = get_global_dof_index(this.values{i}) + this.gdof_offsets(i);
219  end
220  else
221  einds = varargin{1};
222  gids = varargin{2};
223  l = this.nelements;
224  if ~strcmp(einds, ':')
225  l = length(einds);
226  end
227  res = zeros(l, length(gids));
228  for i = 1:length(gids)
229  child_ind = find(this.ldof_offsets < gids(i), 1, 'last');
230  res(:, i) = get_global_dof_index(this.values{child_ind}, ...
231  einds, gids(i) - this.ldof_offsets(child_ind)) + this.gdof_offsets(child_ind);
232  end
233  end
234  end
235 
236  function res = get_dof_ids_global(this, ncomp)
237  % returns global dof ids belonging to one component (indices into
238  % DOF-vector)
239  if length(ncomp) > 1
240  res = get_dof_ids_global(this.values{ncomp(1)}, ncomp(2:end)) + this.gdof_offsets(ncomp(1));
241  elseif length(ncomp) == 1
242  res = get_dof_ids_global(this.values{ncomp}, []) + this.gdof_offsets(ncomp);
243  else
244  res = 1:this.ndofs;
245  end
246  end
247 
248  function df = interpol_local(this, func, params)
249 
250  if nargin<3
251  params = [];
252  end
253 
254  dofs_tmp = cell(1, length(this));
255  for i = 1:length(this)
256  func_tmp = @(varargin)feval(...
257  @(y) y(:, this.dim_offsets(i)+(1:this.values{i}.dimrange)), ...
258  func(varargin{:}));
259  df_tmp = interpol_local(this.values{i}, func_tmp, params);
260  dofs_tmp{i} = df_tmp.dofs(:);
261  end
262 
263  df = Fem.DiscFunc([], this);
264  df.dofs = cat(1, dofs_tmp{:});
265  end
266 
267  end % methods
268 
269 end % classdef
Data Tree element which can be filtered by ids
Definition: IdMapNode.m:18
Composite function space for composition of FE function spaces on same grid.
Abstract class for implementing finite elements. Fem info classes implementing this interface are com...
Definition: IFemInfo.m:18