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
BaseFEM.m
Go to the documentation of this file.
1 namespace fem{
2 
3 
4 /* (Autoinserted by mtoc++)
5  * This source code has been filtered by the mtoc++ executable,
6  * which generates code that can be processed by the doxygen documentation tool.
7  *
8  * On the other hand, it can neither be interpreted by MATLAB, nor can it be compiled with a C++ compiler.
9  * Except for the comments, the function bodies of your M-file functions are untouched.
10  * Consequently, the FILTER_SOURCE_FILES doxygen switch (default in our Doxyfile.template) will produce
11  * attached source files that are highly readable by humans.
12  *
13  * Additionally, links in the doxygen generated documentation to the source code of functions and class members refer to
14  * the correct locations in the source code browser.
15  * However, the line numbers most likely do not correspond to the line numbers in the original MATLAB source files.
16  */
17 
18 class BaseFEM
19  :public handle {
27  public: /* ( Dependent ) */
28 
30 
32 
34 
35 
36  public:
37 
39 
40 
41  Ngp;
52  M;
63  D;
86 
88 
90 
92 
93 
117 
119 
121 
123 
125 
126 
127  private:
128 
129  fGaussPointRule = 3;
130 
131 
132  public:
133 
134  BaseFEM(geometry) {
135  this.Geometry= geometry;
136  this.init;
137  }
138 
139 
140  function init() {
141  g = this.Geometry;
142  el = g.Elements;
143  np = g.NumNodes;
144 
145  /* Get the right gauss points */
146  this.initGaussPoints;
147 
148  /* Build element-dof to global dof assembly matrix */
149  flat_el = el^t;
150  flat_el = flat_el(:)^t;
151  i = []; j = [];
152  for k=1:np
153  idx = find(flat_el == k);
154  i = [i ones(size(idx))*k];/* #ok */
155 
156  j = [j idx];/* #ok */
157 
158  end
159  this.Sigma= sparse(i,j,ones(size(i)),np,g.NumElements*g.DofsPerElement);
160 
161  /* % Precomputations
162  * Number of gauss points */
163  ngp = this.GaussPointsPerElem;
164  Mass = zeros(np,np);
165  Damp = Mass;
166  /* Number of elements */
167  nel = size(el,1);
168  /* nodes per Element */
169  eldofs = size(el,2);
170 
171  /* Basis function evaluation on Gauss points */
172  Ngpval = zeros(eldofs,ngp,nel);
173  /* Jacobian of element deformation at gauss points */
174  eljac = zeros(nel,ngp);
175  /* transformed basis function gradients, stored in eldofs x gp*3
176  * x element matrix (accessible in 20x3-chunks for each gauss point and element) */
177  dtnall = zeros(eldofs,ngp*3,nel);
178  /* Iterate all volumes */
179  for m = 1:nel
180  mass_gp = zeros(eldofs,eldofs);
181  damp_gp = zeros(eldofs,eldofs);
182  elem = el(m,:);
183  /* Iterate all gauss points */
184  for gi = 1:ngp
185  /* gauss point \xi */
186  xi = this.GaussPoints(:,gi);
187 
188  /* % N on gauss points */
189  Ngpval(:,gi,m) = this.N(xi);
190 
191  /* % Jacobian related */
192  dNxi = this.gradN(xi);
193  /* Jacobian of isogeometric mapping */
194  Jac = g.Nodes(:,elem)*dNxi;
195 
196  /* % Mass matrix related
197  * Jacobian at gauss point */
198  eljac(m,gi) = abs(det(Jac));
199 
200  /* Evaluate basis functions at xi */
201  Nxi = this.N(xi);
202 
203  /* Add up [basis function values at xi] times [volume
204  * ratio at xi] times [gauss weight for xi] */
205  mass_gp = mass_gp + this.GaussWeights(gi)*(Nxi*Nxi^t)*eljac(m,gi);
206 
207  /* Add up damping values */
208  damp_gp = damp_gp + this.GaussWeights(gi)*(dNxi*dNxi^t)*eljac(m,gi);
209 
210  /* % Transformed Basis function gradients at xi */
211  dtnall(:,3*(gi-1)+1:3*gi,m) = dNxi / Jac;
212  end
213  /* Build up upper right part of symmetric mass matrix */
214  for j=1:eldofs
215  Mass(elem(j),elem(j:end)) = Mass(elem(j),elem(j:end)) + mass_gp(j,j:end);
216  Damp(elem(j),elem(j:end)) = Damp(elem(j),elem(j:end)) + damp_gp(j,j:end);
217  end
218  end
219  this.Ngp= Ngpval;
220  this.transgrad= dtnall;
221  this.M= sparse(Mass + Mass^t - diag(diag(Mass)));
222  this.D= sparse(Damp + Damp^t - diag(diag(Damp)));
223  this.elem_detjac= eljac;
224 
225  /* % Boundary/Face precomputations */
226  nf = g.NumFaces;
227  ngp = this.GaussPointsPerElemFace;
228  npf = g.NodesPerFace;
229  Ngpval = zeros(npf,ngp,nf);
230  facejac = zeros(nf,ngp);
231  dNN = zeros(npf,ngp,nf);
232  transNormals = zeros(3,ngp,nf);
233  /* tangent dimensions (1st+2nd row) and normal dimension index
234  * (3rd row) */
235  tangidx = [2 2 1 1 1 1;
236  3 3 3 3 2 2];
237  signum = [-1 1 1 -1 -1 1];
238  for fn = 1:nf
239  elemidx = g.Faces(1,fn);
240  faceidx = g.Faces(2,fn);
241  masterfacenodeidx = g.MasterFaces(faceidx,:);
242  /* Get N values on all gauss points of the face, returning a
243  * DofsPerElem x ngp vector. */
244  Nall = this.N(this.FaceGaussPoints(:,:,faceidx));
245  /* From that, we only need the values on the face nodes */
246  Ngpval(:,:,fn) = Nall(masterfacenodeidx,:);
247 
248  dNxi = this.gradN(this.FaceGaussPoints(:,:,faceidx));
249  for gi = 1:ngp
250  dNxipos = [0 ngp 2*ngp]+gi;
251 
252  /* Get full transformation jacobian */
253  Jac = g.Nodes(:,g.Elements(elemidx,:))*dNxi(:,dNxipos);
254 
255  /* Get rotational part of jacobian */
256  [q, ~] = qr(Jac);
257 
258  /* Precompute transformed normals
259  * sign(Jac(tangidx(3,fn),tangidx(3,fn)))... */
260  transNormals(:,gi,fn) = signum(faceidx)...
261  *cross(Jac(:,tangidx(1,faceidx)),Jac(:,tangidx(2,faceidx)));
262 
263  /* Take out rotational part (stretch only) */
264  Jac = q\Jac;
265  /* Take only the restriction of the jacobian to the
266  * face-dimensions for transformation theorem */
267  Jac = Jac(g.FaceDims(:,faceidx),g.FaceDims(:,faceidx));
268 
269  facejac(fn,gi) = abs(det(Jac));
270 
271  /* Precompute transformation of face normals, only the
272  * gradient N * n part (will be left-multiplied with u
273  * at the corresponding locations to get the deformed
274  * normal, can be used for plotting) */
275  dNN(:,gi,fn) = dNxi(masterfacenodeidx,dNxipos) * g.FaceNormals(:,faceidx);
276  end
277  transNormals(:,:,fn) = Norm.normalizeL2(transNormals(:,:,fn));
278  end
279  this.dN_facenormals= dNN;
280  this.face_detjac= facejac;
281  this.FaceAreas= facejac*this.FaceGaussWeights;
282  this.Ngpface= Ngpval;
283  this.NormalsOnFaceGP= transNormals;
284  }
285 
286 
287  function a = getFaceArea(elemidx,faceidx) {
288  g = this.Geometry;
289  a = 0;
290  for k = 1:length(elemidx)
291  a = a + this.FaceAreas(g.Faces(1,:) == elemidx(k) & g.Faces(2,:) == faceidx(k));
292  end
293  }
294 
295 
296  function v = getElementVolume(elemidx) {
297  v = this.elem_detjac(elemidx,:)*this.GaussWeights;
298  }
308  function v = getTotalVolume() {
309  v = sum(this.elem_detjac*this.GaussWeights);
310  }
318  function gp = getGlobalGaussPoints(elemidx) {
319  g = this.Geometry;
320  gp = g.Nodes(:,g.Elements(elemidx,:)) * this.Ngp(:,:,elemidx);
321  }
331  function plot(pm) {
332  if nargin < 2
333  pm = PlotManager(false,2,2);
334  pm.LeaveOpen= true;
335  end
336 
337  h = pm.nextPlot(" mass "," Mass matrix "," node "," node ");
338  mesh(h,full(this.M));
339 
340  pm.nextPlot(" mass_pattern "," Mass matrix pattern "," dof "," dof ");
341  spy(this.M);
342 
343  h = pm.nextPlot(" damp "," Damping matrix "," node "," node ");
344  mesh(h,full(this.D));
345 
346  pm.nextPlot(" damp_pattern "," Damping matrix pattern "," dof "," dof ");
347  spy(this.D);
348 
349  if nargin < 2
350  pm.done;
351  end
352  }
353 
354 
355 
356 #if 0 //mtoc++: 'get.GaussPointRule'
357 function value = GaussPointRule() {
358  value = this.fGaussPointRule;
359  }
360 
361 #endif
362 
363 
364 
365 #if 0 //mtoc++: 'set.GaussPointRule'
366 function GaussPointRule(value) {
367  if ~isequal(this.fGaussPointRule, value)
368 
369  this.fGaussPointRule= value;
370  this.init;
371  end
372  }
373 
374 #endif
375 
376 
377 
378 #if 0 //mtoc++: 'get.GaussPointsPerElem'
379 function nc = GaussPointsPerElem() {
380  nc = size(this.GaussPoints,2);
381  }
382 
383 #endif
384 
385 
386 
387 #if 0 //mtoc++: 'get.GaussPointsPerElemFace'
388 function nc = GaussPointsPerElemFace() {
389  nc = size(this.FaceGaussPoints,2);
390  }
391 
392 #endif
393 
394 
395  public: /* ( Abstract ) */
396 
397  virtual function matrix<double>nx = N(matrix<double> x) = 0;
410  virtual function dnx = gradN(matrix<double> x) = 0;
426  private:
427 
428  function initGaussPoints() {
429  switch this.fGaussPointRule
430  case 3 /* 3-point-rule */
431 
432  g = [-sqrt(3/5) 0 sqrt(3/5)];
433  w = [5/9 8/9 5/9];
434  case 4 /* 4-point-rule */
435 
436  g = [-sqrt(3/7 + 2/7*sqrt(6/5)) -sqrt(3/7 - 2/7*sqrt(6/5)) sqrt(3/7 - 2/7*sqrt(6/5)) sqrt(3/7 + 2/7*sqrt(6/5))];
437  w = [(18-sqrt(30))/36 (18+sqrt(30))/36 (18+sqrt(30))/36 (18-sqrt(30))/36];
438  case 5 /* 5-point rule */
439 
440  a = 2*sqrt(10/7);
441  g = [-sqrt(5+a)/3 -sqrt(5-a)/3 0 sqrt(5-a)/3 sqrt(5+a)/3];
442  a = 13*sqrt(70);
443  w = [(322-a)/900 (322+a)/900 128/225 (322+a)/900 (322-a)/900];
444  case 6
445  /* values from http://pomax.github.io/bezierinfo/legendre-gauss.html */
446  v = [0.3607615730481386 0.6612093864662645
447  0.3607615730481386 -0.6612093864662645
448  0.4679139345726910 -0.2386191860831969
449  0.4679139345726910 0.2386191860831969
450  0.1713244923791704 -0.9324695142031521
451  0.1713244923791704 0.9324695142031521];
452  g = v(:,2)^t;
453  w = v(:,1)^t;
454  case 7
455  v = [0.4179591836734694 0.0000000000000000
456  0.3818300505051189 0.4058451513773972
457  0.3818300505051189 -0.4058451513773972
458  0.2797053914892766 -0.7415311855993945
459  0.2797053914892766 0.7415311855993945
460  0.1294849661688697 -0.9491079123427585
461  0.1294849661688697 0.9491079123427585];
462  g = v(:,2)^t;
463  w = v(:,1)^t;
464  case 8
465  v = [0.3626837833783620 -0.1834346424956498
466  0.3626837833783620 0.1834346424956498
467  0.3137066458778873 -0.5255324099163290
468  0.3137066458778873 0.5255324099163290
469  0.2223810344533745 -0.7966664774136267
470  0.2223810344533745 0.7966664774136267
471  0.1012285362903763 -0.9602898564975363
472  0.1012285362903763 0.9602898564975363];
473  g = v(:,2)^t;
474  w = v(:,1)^t;
475  case 9
476  v = [0.3302393550012598 0.0000000000000000
477  0.1806481606948574 -0.8360311073266358
478  0.1806481606948574 0.8360311073266358
479  0.0812743883615744 -0.9681602395076261
480  0.0812743883615744 0.9681602395076261
481  0.3123470770400029 -0.3242534234038089
482  0.3123470770400029 0.3242534234038089
483  0.2606106964029354 -0.6133714327005904
484  0.2606106964029354 0.6133714327005904];
485  g = v(:,2)^t;
486  w = v(:,1)^t;
487  case 10
488  v = [0.2955242247147529 -0.1488743389816312
489  0.2955242247147529 0.1488743389816312
490  0.2692667193099963 -0.4333953941292472
491  0.2692667193099963 0.4333953941292472
492  0.2190863625159820 -0.6794095682990244
493  0.2190863625159820 0.6794095682990244
494  0.1494513491505806 -0.8650633666889845
495  0.1494513491505806 0.8650633666889845
496  0.0666713443086881 -0.9739065285171717
497  0.0666713443086881 0.9739065285171717];
498  g = v(:,2)^t;
499  w = v(:,1)^t;
500  case 15
501  v = [0.2025782419255613 0.0000000000000000
502  0.1984314853271116 -0.2011940939974345
503  0.1984314853271116 0.2011940939974345
504  0.1861610000155622 -0.3941513470775634
505  0.1861610000155622 0.3941513470775634
506  0.1662692058169939 -0.5709721726085388
507  0.1662692058169939 0.5709721726085388
508  0.1395706779261543 -0.7244177313601701
509  0.1395706779261543 0.7244177313601701
510  0.1071592204671719 -0.8482065834104272
511  0.1071592204671719 0.8482065834104272
512  0.0703660474881081 -0.9372733924007060
513  0.0703660474881081 0.9372733924007060
514  0.0307532419961173 -0.9879925180204854
515  0.0307532419961173 0.9879925180204854];
516  g = v(:,2)^t;
517  w = v(:,1)^t;
518  case 20
519  v = [0.1527533871307258 -0.0765265211334973
520  0.1527533871307258 0.0765265211334973
521  0.1491729864726037 -0.2277858511416451
522  0.1491729864726037 0.2277858511416451
523  0.1420961093183820 -0.3737060887154195
524  0.1420961093183820 0.3737060887154195
525  0.1316886384491766 -0.5108670019508271
526  0.1316886384491766 0.5108670019508271
527  0.1181945319615184 -0.6360536807265150
528  0.1181945319615184 0.6360536807265150
529  0.1019301198172404 -0.7463319064601508
530  0.1019301198172404 0.7463319064601508
531  0.0832767415767048 -0.8391169718222188
532  0.0832767415767048 0.8391169718222188
533  0.0626720483341091 -0.9122344282513259
534  0.0626720483341091 0.9122344282513259
535  0.0406014298003869 -0.9639719272779138
536  0.0406014298003869 0.9639719272779138
537  0.0176140071391521 -0.9931285991850949
538  0.0176140071391521 0.9931285991850949];
539  g = v(:,2)^t;
540  w = v(:,1)^t;
541  otherwise
542  error(" Quadrature rule for %d points per dimension not implemented\nYou can obtain more coefficients from e.g. http://pomax.github.io/bezierinfo/legendre-gauss.html ",this.fGaussPointRule);
543  end
544 
545  /* % Transfer to 3D */
546  [WX,WY,WZ] = meshgrid(w);
547  [GX,GY,GZ] = meshgrid(g);
548  W = WX.*WY.*WZ;
549  this.GaussPoints= [GX(:) GY(:) GZ(:)]^t;
550  this.GaussWeights= W(:);
551 
552  /* Faces Gauss points */
553  [WX,WY] = meshgrid(w);
554  [GX,GY] = meshgrid(g);
555  W = WX.*WY;
556  fgp = zeros(3,length(g)^2,6);
557  faceremainingdim = [-1 1 -1 1 -1 1];
558  g = this.Geometry;
559  for faceidx = 1:6
560  fgp(g.FaceDims(:,faceidx),:,faceidx) = [GX(:) GY(:)]^t;
561  fgp(~g.FaceDims(:,faceidx),:,faceidx) = faceremainingdim(faceidx);
562  end
563  this.FaceGaussPoints= fgp;
564  this.FaceGaussWeights= W(:);
565  }
572  protected: /* ( Static ) */
573 
574  static function res = test_BasisFun(subclass) {
575  h = 1e-8;
576  res = true;
577  for k=1:10
578  a = rand(3,1);
579  A = repmat(a,1,3);
580  diff = (subclass.N(A + h*eye(3)) - subclass.N(A))/h - subclass.gradN(a);
581  res = res & all(diff(:) < 10*h);
582  end
583  }
584 
585 
586  public: /* ( Static ) */
587 
588  static function res = test_JacobiansDefaultGeo() {
589  ranges = [-1:1, -2:1, -2:2];
590  res = true;
591  for k = 1:length(ranges)
592  g = fem.geometry.RegularHex8Grid(ranges[k],ranges[k]);
593  tl = fem.HexahedronTrilinear(g);
594  tq = fem.HexahedronTriquadratic(g.toCube27Node);
595  res = res && norm(tl.elem_detjac-tq.elem_detjac," inf ") < 1e-14;
596  end
597  }
621 };
622 }
623 
624 
625 
function init()
Definition: BaseFEM.m:140
FEMBASE Summary of this class goes here Detailed explanation goes here.
Definition: BaseFEM.m:18
Sigma
The element-dof to global node assembly matrix.
Definition: BaseFEM.m:74
virtual function dnx = gradN(matrix< double > x)
Evaluates the gradients of the elementary basis functions on the master element.
GaussPointRule
Definition: BaseFEM.m:29
BaseFEM(geometry)
Definition: BaseFEM.m:134
D
The damping matrix (for linear damping)
Definition: BaseFEM.m:63
PlotManager: Small class that allows the same plots generated by some script to be either organized a...
Definition: PlotManager.m:17
function plot(pm)
Definition: BaseFEM.m:331
NormalsOnFaceGP
Definition: BaseFEM.m:122
Ngp
Values of basis functions on gauss points.
Definition: BaseFEM.m:41
Matlab's base handle class (documentation generation substitute)
GaussPoints
% Gauss integration related properties
Definition: BaseFEM.m:106
FaceGaussPoints
Definition: BaseFEM.m:118
function a = getFaceArea(elemidx, faceidx)
Definition: BaseFEM.m:287
static function vecs = normalizeL2(vecs)
Definition: Norm.m:53
FaceGaussWeights
Definition: BaseFEM.m:120
Speed test * all(1:3)
transgrad
transformed basis function gradients, stored in eldofs x gp*3 x element matrix (accessible in 20x3-ch...
Definition: BaseFEM.m:94
dN_facenormals
Definition: BaseFEM.m:91
function v = getElementVolume(elemidx)
Returns the volume of the element with the specified index in [mm³].
Definition: BaseFEM.m:296
function v = getTotalVolume()
Returns the total geometry volume in [mm³].
Definition: BaseFEM.m:308
function gp = getGlobalGaussPoints(elemidx)
Returns the positions of all gauss points of the specified element in global (=reference) coordinates...
Definition: BaseFEM.m:318
virtual function matrix< double > nx = N(matrix< double > x)
Evaluates the elementary basis functions on the geometry master element.
GaussPointsPerElemFace
Definition: BaseFEM.m:33
GaussPointsPerElem
Definition: BaseFEM.m:31
Norm: Static class for commonly used norms on sets of vectors.
Definition: Norm.m:17
static function res = test_JacobiansDefaultGeo()
Tests if the deformation jacobians using linear and quadratic elements is the same for a default geom...
Definition: BaseFEM.m:588
M
The mass matrix.
Definition: BaseFEM.m:52
static function res = test_BasisFun(subclass)
Definition: BaseFEM.m:574