comparison +multiblock/DiffOp.m @ 707:0de70ec8bf60 feature/quantumTriangles

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