Mercurial > repos > public > sbplib
comparison +multiblock/DiffOp.m @ 820:501750fbbfdb
Merge with feature/grids
author | Jonatan Werpers <jonatan@werpers.com> |
---|---|
date | Fri, 07 Sep 2018 14:40:58 +0200 |
parents | 5cf9fdf4c98f |
children | 57760d7088ad 7d4f57725192 |
comparison
equal
deleted
inserted
replaced
819:fdf0ef9150f4 | 820:501750fbbfdb |
---|---|
1 classdef DiffOp < scheme.Scheme | |
2 properties | |
3 grid | |
4 order | |
5 diffOps | |
6 D | |
7 H | |
8 | |
9 blockmatrixDiv | |
10 end | |
11 | |
12 methods | |
13 function obj = DiffOp(doHand, g, order, doParam) | |
14 % doHand -- may either be a function handle or a cell array of | |
15 % function handles for each grid. The function handle(s) | |
16 % should be on the form do = doHand(grid, order, ...) | |
17 % Additional parameters for each doHand may be provided in | |
18 % the doParam input. | |
19 % g -- a multiblock grid | |
20 % order -- integer specifying the order of accuracy | |
21 % doParam -- may either be a cell array or a cell array of cell arrays | |
22 % for each block. If it is a cell array with length equal | |
23 % to the number of blocks then each element is sent to the | |
24 % corresponding function handle as extra parameters: | |
25 % doHand(..., doParam{i}{:}) Otherwise doParam is sent as | |
26 % extra parameters to all doHand: doHand(..., doParam{:}) | |
27 default_arg('doParam', []) | |
28 | |
29 [getHand, getParam] = parseInput(doHand, g, doParam); | |
30 | |
31 nBlocks = g.nBlocks(); | |
32 | |
33 obj.order = order; | |
34 | |
35 % Create the diffOps for each block | |
36 obj.diffOps = cell(1, nBlocks); | |
37 for i = 1:nBlocks | |
38 h = getHand(i); | |
39 p = getParam(i); | |
40 if ~iscell(p) | |
41 p = {p}; | |
42 end | |
43 obj.diffOps{i} = h(g.grids{i}, order, p{:}); | |
44 end | |
45 | |
46 | |
47 % Build the norm matrix | |
48 H = cell(nBlocks, nBlocks); | |
49 for i = 1:nBlocks | |
50 H{i,i} = obj.diffOps{i}.H; | |
51 end | |
52 obj.H = blockmatrix.toMatrix(H); | |
53 | |
54 | |
55 % Build the differentiation matrix | |
56 Ns = zeros(nBlocks,1); | |
57 for i = 1:nBlocks | |
58 Ns(i) = length(obj.diffOps{i}.D); | |
59 end | |
60 obj.blockmatrixDiv = {Ns, Ns}; | |
61 D = blockmatrix.zero(obj.blockmatrixDiv); | |
62 for i = 1:nBlocks | |
63 D{i,i} = obj.diffOps{i}.D; | |
64 end | |
65 | |
66 for i = 1:nBlocks | |
67 for j = 1:nBlocks | |
68 intf = g.connections{i,j}; | |
69 if isempty(intf) | |
70 continue | |
71 end | |
72 | |
73 | |
74 [ii, ij] = obj.diffOps{i}.interface(intf{1}, obj.diffOps{j}, intf{2}); | |
75 D{i,i} = D{i,i} + ii; | |
76 D{i,j} = D{i,j} + ij; | |
77 | |
78 [jj, ji] = obj.diffOps{j}.interface(intf{2}, obj.diffOps{i}, intf{1}); | |
79 D{j,j} = D{j,j} + jj; | |
80 D{j,i} = D{j,i} + ji; | |
81 end | |
82 end | |
83 obj.D = blockmatrix.toMatrix(D); | |
84 obj.grid = g; | |
85 | |
86 | |
87 function [getHand, getParam] = parseInput(doHand, g, doParam) | |
88 if ~isa(g, 'multiblock.Grid') | |
89 error('multiblock:DiffOp:DiffOp:InvalidGrid', 'Requires a multiblock grid.'); | |
90 end | |
91 | |
92 if iscell(doHand) && length(doHand) == g.nBlocks() | |
93 getHand = @(i)doHand{i}; | |
94 elseif isa(doHand, 'function_handle') | |
95 getHand = @(i)doHand; | |
96 else | |
97 error('multiblock:DiffOp:DiffOp:InvalidGridDoHand', 'doHand must be a function handle or a cell array of length grid.nBlocks'); | |
98 end | |
99 | |
100 if isempty(doParam) | |
101 getParam = @(i){}; | |
102 return | |
103 end | |
104 | |
105 if ~iscell(doParam) | |
106 getParam = @(i)doParam; | |
107 return | |
108 end | |
109 | |
110 % doParam is a non-empty cell-array | |
111 | |
112 if length(doParam) == g.nBlocks() && all(cellfun(@iscell, doParam)) | |
113 % doParam is a cell-array of cell-arrays | |
114 getParam = @(i)doParam{i}; | |
115 return | |
116 end | |
117 | |
118 getParam = @(i)doParam; | |
119 end | |
120 end | |
121 | |
122 function ops = splitOp(obj, op) | |
123 % Splits a matrix operator into a cell-matrix of matrix operators for | |
124 % each grid. | |
125 ops = sparse2cell(op, obj.NNN); | |
126 end | |
127 | |
128 % Get a boundary operator specified by opName for the given boundary/BoundaryGroup | |
129 function op = getBoundaryOperator(obj, opName, boundary) | |
130 switch class(boundary) | |
131 case 'cell' | |
132 localOpName = [opName '_' boundary{2}]; | |
133 blockId = boundary{1}; | |
134 localOp = obj.diffOps{blockId}.(localOpName); | |
135 | |
136 div = {obj.blockmatrixDiv{1}, size(localOp,2)}; | |
137 blockOp = blockmatrix.zero(div); | |
138 blockOp{blockId,1} = localOp; | |
139 op = blockmatrix.toMatrix(blockOp); | |
140 return | |
141 case 'multiblock.BoundaryGroup' | |
142 op = sparse(size(obj.D,1),0); | |
143 for i = 1:length(boundary) | |
144 op = [op, obj.getBoundaryOperator(opName, boundary{i})]; | |
145 end | |
146 otherwise | |
147 error('Unknown boundary indentifier') | |
148 end | |
149 end | |
150 | |
151 function op = getBoundaryQuadrature(obj, boundary) | |
152 opName = 'H'; | |
153 switch class(boundary) | |
154 case 'cell' | |
155 localOpName = [opName '_' boundary{2}]; | |
156 blockId = boundary{1}; | |
157 op = obj.diffOps{blockId}.(localOpName); | |
158 | |
159 return | |
160 case 'multiblock.BoundaryGroup' | |
161 N = length(boundary); | |
162 H_bm = cell(N,N); | |
163 for i = 1:N | |
164 H_bm{i,i} = obj.getBoundaryQuadrature(boundary{i}); | |
165 end | |
166 op = blockmatrix.toMatrix(H_bm); | |
167 otherwise | |
168 error('Unknown boundary indentifier') | |
169 end | |
170 end | |
171 | |
172 % Creates the closure and penalty matrix for a given boundary condition, | |
173 % boundary -- the name of the boundary on the form {id,name} where | |
174 % id is the number of a block and name is the name of a | |
175 % boundary of that block example: {1,'s'} or {3,'w'}. It | |
176 % can also be a boundary group | |
177 function [closure, penalty] = boundary_condition(obj, boundary, type) | |
178 switch class(boundary) | |
179 case 'cell' | |
180 [closure, penalty] = obj.singleBoundaryCondition(boundary, type); | |
181 case 'multiblock.BoundaryGroup' | |
182 [n,m] = size(obj.D); | |
183 closure = sparse(n,m); | |
184 penalty = sparse(n,0); | |
185 for i = 1:length(boundary) | |
186 [closurePart, penaltyPart] = obj.boundary_condition(boundary{i}, type); | |
187 closure = closure + closurePart; | |
188 penalty = [penalty, penaltyPart]; | |
189 end | |
190 otherwise | |
191 error('Unknown boundary indentifier') | |
192 end | |
193 | |
194 end | |
195 | |
196 function [closure, penalty] = singleBoundaryCondition(obj, boundary, type) | |
197 I = boundary{1}; | |
198 name = boundary{2}; | |
199 | |
200 % Get the closure and penaly matrices | |
201 [blockClosure, blockPenalty] = obj.diffOps{I}.boundary_condition(name, type); | |
202 | |
203 % Expand to matrix for full domain. | |
204 div = obj.blockmatrixDiv; | |
205 if ~iscell(blockClosure) | |
206 temp = blockmatrix.zero(div); | |
207 temp{I,I} = blockClosure; | |
208 closure = blockmatrix.toMatrix(temp); | |
209 else | |
210 for i = 1:length(blockClosure) | |
211 temp = blockmatrix.zero(div); | |
212 temp{I,I} = blockClosure{i}; | |
213 closure{i} = blockmatrix.toMatrix(temp); | |
214 end | |
215 end | |
216 | |
217 if ~iscell(blockPenalty) | |
218 div{2} = size(blockPenalty, 2); % Penalty is a column vector | |
219 p = blockmatrix.zero(div); | |
220 p{I} = blockPenalty; | |
221 penalty = blockmatrix.toMatrix(p); | |
222 else | |
223 % TODO: used by beam equation, should be eliminated. SHould only set one BC per call | |
224 for i = 1:length(blockPenalty) | |
225 div{2} = size(blockPenalty{i}, 2); % Penalty is a column vector | |
226 p = blockmatrix.zero(div); | |
227 p{I} = blockPenalty{i}; | |
228 penalty{i} = blockmatrix.toMatrix(p); | |
229 end | |
230 end | |
231 end | |
232 | |
233 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary) | |
234 error('not implemented') | |
235 end | |
236 | |
237 % Size returns the number of degrees of freedom | |
238 function N = size(obj) | |
239 N = 0; | |
240 for i = 1:length(obj.diffOps) | |
241 N = N + obj.diffOps{i}.size(); | |
242 end | |
243 end | |
244 end | |
245 end |