KerMor  0.9
Model order reduction for nonlinear dynamical systems and nonlinear approximation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Belly.m
Go to the documentation of this file.
1 namespace fem{
2 namespace geometry{
3 
4 
5 /* (Autoinserted by mtoc++)
6  * This source code has been filtered by the mtoc++ executable,
7  * which generates code that can be processed by the doxygen documentation tool.
8  *
9  * On the other hand, it can neither be interpreted by MATLAB, nor can it be compiled with a C++ compiler.
10  * Except for the comments, the function bodies of your M-file functions are untouched.
11  * Consequently, the FILTER_SOURCE_FILES doxygen switch (default in our Doxyfile.template) will produce
12  * attached source files that are highly readable by humans.
13  *
14  * Additionally, links in the doxygen generated documentation to the source code of functions and class members refer to
15  * the correct locations in the source code browser.
16  * However, the line numbers most likely do not correspond to the line numbers in the original MATLAB source files.
17  */
18 
19 function geo27 = Belly(parts,len,varargin) {
20 
21 i.KeepUnmatched= true;
22 i.addParamValue('Radius',1);
23 i.addParamValue('InnerRadius',.5);
24 i.addParamValue('Gamma',2);
25 i.addParamValue('Layers',1);
26 i.addParamValue('MinZ',[]);
27 i.parse(varargin[:]);
28 opt = i.Results;
29 if nargin < 2
30  len = 10;
31  if nargin < 1
32  parts = 4;
33  end
34 end
35 if numel(len) == 2
36  x = linspace(len(1),len(2),parts*2+1);
37 else
38  x = linspace(0,len,parts*2+1);
39 end
40 if isa(opt.Radius," function_handle ")
41  fx = opt.Radius(x);
42  if size(fx,1) == 1
43  fx = [fx; fx];
44  end
45 else
46  if isscalar(opt.Gamma)
47  opt.Gamma= [opt.Gamma opt.Gamma];
48  end
49  if isscalar(opt.Radius)
50  opt.Radius= [opt.Radius opt.Radius];
51  end
52  k = kernels.GaussKernel;
53  k.Gamma= opt.Gamma(1);
54  fx(1,:) = k.evaluate(x,len/2)^t*opt.Radius(1);
55  k.Gamma= opt.Gamma(2);
56  fx(2,:) = k.evaluate(x,len/2)^t*opt.Radius(2);
57 end
58 if isscalar(opt.InnerRadius)
59  opt.InnerRadius= [1 1]*opt.InnerRadius;
60 end
61 
62 posfun = @(omega,offset)[sin(omega+offset); cos(omega+offset)];
63 
64 qpart = getQuarterPart(opt.Layers);
65 baseelems = zeros(size(qpart,1),size(qpart,2),4);
66 baseelems(:,:,1) = qpart;
67 nelems = size(baseelems,1)/2;
68 for k=1:nelems
69  pos = (1:2)+2*(k-1);
70  baseelems(pos,:,2) = [-1 0; 0 1]*baseelems(pos,[3 2 1 6 5 4 9 8 7],1);
71 end
72 baseelems(:,:,3) = -baseelems(:,9:-1:1,1);
73 baseelems(:,:,4) = -baseelems(:,9:-1:1,2);
74 
75 /* c = sin(pi/4);
76  * c8 = cos(pi/8);
77  * s8 = sin(pi/8);
78  * baseplane(:,:,1) = [0 .5 1 0 .5*c c8 0 s8 c
79  * 0 0 0 .5 .5*c s8 1 c8 c];
80  * % Mirror first segment
81  * baseplane(:,:,2) = [-1 0; 0 1]*baseplane(:,[3 2 1 6 5 4 9 8 7],1);
82  * % Rotate others by 180°
83  * baseplane(:,:,3) = -baseplane(:,9:-1:1,1);
84  * baseplane(:,:,4) = -baseplane(:,9:-1:1,2); */
85 
86 npp = 27*parts*nelems;
87 nodes = zeros(3,npp*4);
88 for p = 1:parts
89  elempos = (p-1)*2 + (1:3);
90  rx = ones(9,1) * (opt.InnerRadius(1) + fx(1,elempos));
91  ry = ones(9,1) * (opt.InnerRadius(2) + fx(2,elempos));
92  z = ones(9,1) * x(elempos);
93  for k=1:nelems
94  elem = baseelems((1:2)+2*(k-1),:,:);
95  for rotpart = 1:4
96  nodepos = (((p-1) * nelems + (k-1))*4 + (rotpart-1))*27 + (1:27);
97  nodes(1,nodepos) = bsxfun(@times,repmat(elem(1,:,rotpart),1,3),rx(:)^t);
98  nodes(2,nodepos) = bsxfun(@times,repmat(elem(2,:,rotpart),1,3),ry(:)^t);
99  nodes(3,nodepos) = z(:);
100  end
101  end
102 end
103 
104 /* Filter nodes to unique ones */
105 [nodes, ~, elems] = unique(nodes" , "rows" , "stable^t);
106 
107 /* For the "not so unique but same" nodes use pdist */
108 D = pdist(nodes);
109 [D, idx] = sort(D," ascend ");
110 same = D < eps*max(D);
111 [i,j] = find(tril(ones(size(nodes,1)),-1));
112 i = i(idx(same)); j = j(idx(same));
113 /* Kick out double nodes */
114 nodes(j,:) = [];
115 /* Correct element indices after node removal
116  * - use i indices (instead of to-remove-j) */
117 for k=1:length(i)
118  elems(elems == j(k)) = i(k);
119 end
120 /* - Get effective number of nodes */
121 effidx = unique(elems(:));
122 /* - Set mapping indices at old positions */
123 invidx(effidx) = 1:length(effidx);
124 /* - Use those! */
125 elems = invidx(elems);
126 
127 /* Get the right shape */
128 nodes = nodes^t;
129 elems = reshape(elems,27,[])^t;
130 
131 /* This little hack allows to restrict the minimum z node
132  * position to a certain value, so as if the muscle belly is
133  * "lying on a table"
134  *
135  * This only works on the "downside" faces, so if the threshold
136  * is larger than the intermediate node position of the side
137  * faces, the muscle geometry will appear "dented". */
138 if ~isempty(opt.MinZ)
139  error(" Fixme ");
140  hlp_g27 = fem.geometry.Cube27Node;
141  centerline_facenodeidx = hlp_g27.MasterFaces(3,:);
142  for elem = [3:4:4*parts 4:4:4*parts]
143  centerline_nodes = elems(elem,centerline_facenodeidx);
144  toScale = nodes(2,centerline_nodes) < opt.MinZ;
145  factor = opt.MinZ./nodes(2,centerline_nodes(toScale));
146  nodes(2,centerline_nodes(toScale)) = opt.MinZ;
147  /* Also scale inner node positions */
148  inner_nodes = elems(elem,[4:6 13:15 22:24]);
149  nodes(2,inner_nodes(toScale)) = nodes(2,inner_nodes(toScale)).*factor;
150  end
151 end
152 
153 geo27 = fem.geometry.Cube27Node(nodes,elems);
154 geo27.swapYZ;
155 
156  function elems = getQuarterPart(elem_layers)
157  if nargin < 1
158  elem_layers = 9;
159  end
160  if isscalar(elem_layers)
161  elem_layers = linspace(0,1,elem_layers+1);
162  elem_layers = elem_layers(2:end);
163  end
164  elem_layers = elem_layers / max(elem_layers);
165  num_elem_layers = length(elem_layers);
166 
167  /* Augment layer count if odd */
168  if mod(num_elem_layers,2) == 1
169  elem_layers(end+1) = elem_layers(end)*1.1;
170  end
171 
172  /* Create innermost element */
173  o = posfun(linspace(0,pi/2,5),0);
174  c = posfun(pi/4,0)/2;
175  elems(1:2,:) = [0 .5 1 0 c(1) o(1,4) o(1,1:3)
176  0 0 0 .5 c(2) o(2,4) o(2,1:3)]*elem_layers(1);
177 
178  if num_elem_layers > 1
179  o = elem_layers(2)*posfun(linspace(0,pi/2,5),0);
180  elems(3:4,:) = [elems(1:2,7:9) (o(:,1:3)+elems(1:2,7:9))/2 o(:,1:3)];
181  elems(5:6,:) = [elems(1:2,[9 6 3]) (o(:,3:5)+elems(1:2,[9 6 3]))/2 o(:,3:5)];
182  /* Reorder */
183  elems(5:6,:) = elems(5:6,[3 6 9 2 5 8 1 4 7]);
184  end
185 
186  /* number of blocks needed (two elem layers per block) */
187  num_block_layers = ceil(num_elem_layers/2)-1;
188 
189  omega = pi/2;
190  blocks_per_loop = 1;
191  for bn=1:num_block_layers
192  layerpos = (2:4)+2*(bn-1);
193  for b = 1:blocks_per_loop
194  off = (b-1)*omega;
195  new = getblock(elem_layers(layerpos),omega,off);
196  if bn == num_block_layers && mod(num_elem_layers,2) ~= 0
197  /* Cut out the outer layer if not wanted */
198  new = new(1:6,:);
199  end
200  elems(end+1:end+size(new,1),:) = new;
201  end
202  omega = omega / 2;
203  blocks_per_loop = blocks_per_loop*2;
204  end
205  end
206 
207  function elems = getblock(radii,omega,offset)
208  i = radii(1)*posfun(linspace(0,omega,5),offset);
209  m = radii(2)*posfun(linspace(0,omega,13),offset);
210  m = m(:,[1 3 5:9 11 13]);
211  o = radii(3)*posfun(linspace(0,omega,9),offset);
212 
213  /* E1 */
214  elems(1:2,:) = [i(:,1:3) (m(:,1:3)+i(:,1:3))/2 m(:,1:3)];
215  /* E3 */
216  elems(5:6,:) = [i(:,3:5) (m(:,7:9)+i(:,3:5))/2 m(:,7:9)];
217  center = (radii(1)+radii(2))/2*posfun(omega/2,offset);
218  /* E2 (split part) */
219  elems(3:4,:) = [elems(5:6,[1 4 7]) elems(1:2,6) center m(:,[6 3:5])];
220 
221  /* E4-E7 top layer */
222  elems(7:8,:) = [elems(1:2,7:9) (o(:,1:3)+elems(1:2,7:9))/2 o(:,1:3)];
223  elems(9:10,:) = [elems(3:4,7:9) (o(:,3:5)+elems(3:4,7:9))/2 o(:,3:5)];
224  elems(11:12,:) = [elems(3:4,[9 6 3]) (o(:,5:7)+elems(3:4,[9 6 3]))/2 o(:,5:7)];
225  elems(13:14,:) = [elems(5:6,7:9) (o(:,7:9)+elems(5:6,7:9))/2 o(:,7:9)];
226 
227  /* Reorder for x-axis increase first
228  *elems(5:6,:) = elems(5:6,[3 6 9 2 5 8 1 4 7]);
229  *elems(11:12,:) = elems(11:12,[3 6 9 2 5 8 1 4 7]);
230  *elems(13:14,:) = elems(13:14,[3 6 9 2 5 8 1 4 7]); */
231  end
232 end
233 
234 
235 }
261 };
262 };
function geo27 = Belly(parts, len, varargin)
Code to generate a belly-shaped geometry with various options.
Definition: Belly.m:19
A variable number of input arguments.