gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
nodalBasis.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <limits>
7 #include <cmath>
8 #include <algorithm>
9 #include "nodalBasis.h"
10 #include "BasisFactory.h"
11 #include "pointsGenerators.h"
12 #include "MPrism.h"
13 
14 namespace ClosureGen {
15  inline double pow2(double x) { return x * x; }
16 
17  void rotateHex(int iFace, int iRot, int iSign, double uI, double vI,
18  double &uO, double &vO, double &wO)
19  {
20  if(iSign < 0) {
21  double tmp = uI;
22  uI = vI;
23  vI = tmp;
24  }
25  for(int i = 0; i < iRot; i++) {
26  double tmp = uI;
27  uI = -vI;
28  vI = tmp;
29  }
30  switch(iFace) {
31  case 0:
32  uO = vI;
33  vO = uI;
34  wO = -1;
35  break;
36  case 1:
37  uO = uI;
38  vO = -1;
39  wO = vI;
40  break;
41  case 2:
42  uO = -1;
43  vO = vI;
44  wO = uI;
45  break;
46  case 3:
47  uO = 1;
48  vO = uI;
49  wO = vI;
50  break;
51  case 4:
52  uO = -uI;
53  vO = 1;
54  wO = vI;
55  break;
56  case 5:
57  uO = uI;
58  vO = vI;
59  wO = 1;
60  break;
61  }
62  }
63 
64  void rotateHexFull(int iFace, int iRot, int iSign, double uI, double vI,
65  double wI, double &uO, double &vO, double &wO)
66  {
67  switch(iFace) {
68  case 0:
69  uO = uI;
70  vO = vI;
71  wO = wI;
72  break;
73  case 1:
74  uO = wI;
75  vO = uI;
76  wO = vI;
77  break;
78  case 2:
79  uO = vI;
80  vO = wI;
81  wO = uI;
82  break;
83  case 3:
84  uO = wI;
85  vO = vI;
86  wO = -uI;
87  break;
88  case 4:
89  uO = wI;
90  vO = -uI;
91  wO = -vI;
92  break;
93  case 5:
94  uO = vI;
95  vO = uI;
96  wO = -wI;
97  break;
98  }
99  for(int i = 0; i < iRot; i++) {
100  double tmp = uO;
101  uO = -vO;
102  vO = tmp;
103  }
104  if(iSign < 0) {
105  double tmp = uO;
106  uO = vO;
107  vO = tmp;
108  }
109  }
110 
111  void rotatePyr(int iFace, int iRot, int iSign, double uI, double vI,
112  double &uO, double &vO, double &wO)
113  {
114  if(iSign < 0) {
115  double tmp = uI;
116  uI = vI;
117  vI = tmp;
118  }
119  for(int i = 0; i < iRot; i++) {
120  double tmp = uI;
121  uI = -vI;
122  vI = tmp;
123  }
124  switch(iFace) {
125  case 0:
126  uO = uI;
127  vO = vI - 1;
128  wO = vI;
129  break;
130  case 1:
131  uO = vI - 1;
132  vO = -uI;
133  wO = vI;
134  break;
135  case 2:
136  uO = 1 - vI;
137  vO = uI;
138  wO = vI;
139  break;
140  case 3:
141  uO = -uI;
142  vO = 1 - vI;
143  wO = vI;
144  break;
145  case 4:
146  uO = vI;
147  vO = uI;
148  wO = 0;
149  break;
150  }
151  }
152 
153  void generate1dVertexClosure(nodalBasis::clCont &closure, int order)
154  {
155  closure.clear();
156  closure.resize(2);
157  closure[0].push_back(0);
158  closure[1].push_back(order == 0 ? 0 : 1);
159  closure[0].type = MSH_PNT;
160  closure[1].type = MSH_PNT;
161  }
162 
164  std::vector<int> &closureRef, int order)
165  {
166  closure.clear();
167  closure.resize(2);
168  closure[0].push_back(0);
169  if(order != 0) {
170  closure[0].push_back(1);
171  closure[1].push_back(1);
172  }
173  closure[1].push_back(0);
174  for(int i = 0; i < order - 1; i++) {
175  closure[0].push_back(2 + i);
176  closure[1].push_back(2 + order - 2 - i);
177  }
178  closureRef.resize(2);
179  closureRef[0] = 0;
180  closureRef[1] = 0;
181  }
182 
183  void getFaceClosureTet(int iFace, int iSign, int iRotate,
184  nodalBasis::closure &closure, int order)
185  {
186  closure.clear();
187  closure.resize((order + 1) * (order + 2) / 2);
188  closure.type = ElementType::getType(TYPE_TRI, order, false);
189 
190  switch(order) {
191  case 0: closure[0] = 0; break;
192  default:
193  int face[4][3] = {{-3, -2, -1}, {1, -6, 4}, {-4, 5, 3}, {6, 2, -5}};
194  int order1node[4][3] = {{0, 2, 1}, {0, 1, 3}, {0, 3, 2}, {3, 1, 2}};
195  for(int i = 0; i < 3; ++i) {
196  int k = (3 + (iSign * i) + iRotate) % 3; //- iSign * iRotate
197  closure[i] = order1node[iFace][k];
198  }
199  for(int i = 0; i < 3; ++i) {
200  int edgenumber =
201  iSign * face[iFace][(6 + i * iSign + (-1 + iSign) / 2 + iRotate) %
202  3]; //- iSign * iRotate
203  for(int k = 0; k < (order - 1); k++) {
204  if(edgenumber > 0)
205  closure[3 + i * (order - 1) + k] =
206  4 + (edgenumber - 1) * (order - 1) + k;
207  else
208  closure[3 + i * (order - 1) + k] =
209  4 + (-edgenumber) * (order - 1) - 1 - k;
210  }
211  }
212  int fi = 3 + 3 * (order - 1);
213  int ti = 4 + 6 * (order - 1);
214  int ndofff = (order - 3 + 2) * (order - 3 + 1) / 2;
215  ti = ti + iFace * ndofff;
216  for(int k = 0; k < order / 3; k++) {
217  int orderint = order - 3 - k * 3;
218  if(orderint > 0) {
219  for(int ci = 0; ci < 3; ci++) {
220  int shift = (3 + iSign * ci + iRotate) % 3; //- iSign * iRotate
221  closure[fi + ci] = ti + shift;
222  }
223  fi = fi + 3;
224  ti = ti + 3;
225  for(int l = 0; l < orderint - 1; l++) {
226  for(int ei = 0; ei < 3; ei++) {
227  int edgenumber =
228  (6 + ei * iSign + (-1 + iSign) / 2 + iRotate) % 3;
229  //- iSign * iRotate
230  if(iSign > 0)
231  closure[fi + ei * (orderint - 1) + l] =
232  ti + edgenumber * (orderint - 1) + l;
233  else
234  closure[fi + ei * (orderint - 1) + l] =
235  ti + (1 + edgenumber) * (orderint - 1) - 1 - l;
236  }
237  }
238  fi = fi + 3 * (orderint - 1);
239  ti = ti + 3 * (orderint - 1);
240  }
241  else {
242  closure[fi] = ti;
243  ti++;
244  fi++;
245  }
246  }
247  break;
248  }
249  }
250 
252  std::vector<int> &closureRef, int order,
253  int nNod, bool serendip)
254  {
255  closure.clear();
256  closure.resize(2 * nNod);
257  closureRef.resize(2 * nNod);
258  int shift = 0;
259  for(int corder = order; corder >= 0; corder -= (nNod == 3 ? 3 : 2)) {
260  if(corder == 0) {
261  for(int r = 0; r < nNod; r++) {
262  closure[r].push_back(shift);
263  closure[r + nNod].push_back(shift);
264  }
265  break;
266  }
267  for(int r = 0; r < nNod; r++) {
268  for(int j = 0; j < nNod; j++) {
269  closure[r].push_back(shift + (r + j) % nNod);
270  closure[r + nNod].push_back(shift + (r - j + 1 + nNod) % nNod);
271  }
272  }
273  shift += nNod;
274  int n = nNod * (corder - 1);
275  for(int r = 0; r < nNod; r++) {
276  for(int j = 0; j < n; j++) {
277  closure[r].push_back(shift + (j + (corder - 1) * r) % n);
278  closure[r + nNod].push_back(shift +
279  (n - j - 1 + (corder - 1) * (r + 1)) % n);
280  }
281  }
282  shift += n;
283  if(serendip) break;
284  }
285  for(int r = 0; r < nNod * 2; r++) {
286  closure[r].type = ElementType::getType(TYPE_LIN, order);
287  closureRef[r] = 0;
288  }
289  }
290 
291  void addEdgeNodes(nodalBasis::clCont &closureFull, const int *edges,
292  int order)
293  {
294  if(order < 2) return;
295  int numNodes = 0;
296  for(int i = 0; edges[i] >= 0; ++i) {
297  numNodes = std::max(numNodes, edges[i] + 1);
298  }
299  std::vector<std::vector<int> > nodes2edges(numNodes,
300  std::vector<int>(numNodes, -1));
301  for(int i = 0; edges[i] >= 0; i += 2) {
302  nodes2edges[edges[i]][edges[i + 1]] = i;
303  nodes2edges[edges[i + 1]][edges[i]] = i + 1;
304  }
305  for(std::size_t iClosure = 0; iClosure < closureFull.size(); iClosure++) {
306  std::vector<int> &cl = closureFull[iClosure];
307  for(int iEdge = 0; edges[iEdge] >= 0; iEdge += 2) {
308  if(cl.empty()) continue;
309  int n0 = cl[edges[iEdge]];
310  int n1 = cl[edges[iEdge + 1]];
311  int oEdge = nodes2edges[n0][n1];
312  if(oEdge == -1) Msg::Error("invalid p1 closure or invalid edges list");
313  for(int i = 0; i < order - 1; i++)
314  cl.push_back(numNodes + oEdge / 2 * (order - 1) +
315  ((oEdge % 2) ? order - 2 - i : i));
316  }
317  }
318  }
319 
320  void generateFaceClosureTet(nodalBasis::clCont &closure, int order)
321  {
322  closure.clear();
323  for(int iRotate = 0; iRotate < 3; iRotate++) {
324  for(int iSign = 1; iSign >= -1; iSign -= 2) {
325  for(int iFace = 0; iFace < 4; iFace++) {
326  nodalBasis::closure closure_face;
327  getFaceClosureTet(iFace, iSign, iRotate, closure_face, order);
328  closure.push_back(closure_face);
329  }
330  }
331  }
332  }
333 
335  std::vector<int> &closureRef, int order,
336  bool serendip)
337  {
338  closureFull.clear();
339  // input :
340  static const short int faces[4][3] = {
341  {0, 1, 2}, {0, 3, 1}, {0, 2, 3}, {3, 2, 1}};
342  static const int edges[] = {0, 1, 1, 2, 2, 0, 3, 0, 3, 2, 3, 1, -1};
343  static const int faceOrientation[6] = {0, 1, 2, 5, 3, 4};
344  closureFull.resize(24);
345  closureRef.resize(24);
346  for(int i = 0; i < 24; i++) closureRef[i] = 0;
347  if(order == 0) {
348  for(int i = 0; i < 24; i++) { closureFull[i].push_back(0); }
349  return;
350  }
351  // Mapping for the p1 nodes
352  nodalBasis::clCont closure;
353  generateFaceClosureTet(closure, 1);
354  for(std::size_t i = 0; i < closureFull.size(); i++) {
355  std::vector<int> &clFull = closureFull[i];
356  std::vector<int> &cl = closure[i];
357  clFull.resize(4, -1);
358  closureRef[i] = 0;
359  for(std::size_t j = 0; j < cl.size(); j++) clFull[closure[0][j]] = cl[j];
360  for(int j = 0; j < 4; j++)
361  if(clFull[j] == -1)
362  clFull[j] = (6 - clFull[(j + 1) % 4] - clFull[(j + 2) % 4] -
363  clFull[(j + 3) % 4]);
364  }
365  int nodes2Faces[4][4][4];
366  for(int i = 0; i < 4; i++) {
367  for(int iRotate = 0; iRotate < 3; iRotate++) {
368  short int n0 = faces[i][(3 - iRotate) % 3];
369  short int n1 = faces[i][(4 - iRotate) % 3];
370  short int n2 = faces[i][(5 - iRotate) % 3];
371  nodes2Faces[n0][n1][n2] = i * 6 + iRotate;
372  nodes2Faces[n0][n2][n1] = i * 6 + iRotate + 3;
373  }
374  }
375  nodalBasis::clCont closureTriangles;
376  std::vector<int> closureTrianglesRef;
377  if(order >= 3)
378  generate2dEdgeClosureFull(closureTriangles, closureTrianglesRef,
379  order - 3, 3, false);
380  addEdgeNodes(closureFull, edges, order);
381  for(std::size_t iClosure = 0; iClosure < closureFull.size(); iClosure++) {
382  // faces
383  std::vector<int> &cl = closureFull[iClosure];
384  if(order >= 3) {
385  for(int iFace = 0; iFace < 4; iFace++) {
386  int n0 = cl[faces[iFace][0]];
387  int n1 = cl[faces[iFace][1]];
388  int n2 = cl[faces[iFace][2]];
389  short int id = nodes2Faces[n0][n1][n2];
390  short int iTriClosure = faceOrientation[id % 6];
391  short int idFace = id / 6;
392  int nOnFace = closureTriangles[iTriClosure].size();
393  for(int i = 0; i < nOnFace; i++) {
394  cl.push_back(4 + 6 * (order - 1) + idFace * nOnFace +
395  closureTriangles[iTriClosure][i]);
396  }
397  }
398  }
399  }
400  if(order >= 4 && !serendip) {
401  nodalBasis::clCont insideClosure;
402  std::vector<int> fakeClosureRef;
403  generateFaceClosureTetFull(insideClosure, fakeClosureRef, order - 4,
404  false);
405  for(std::size_t i = 0; i < closureFull.size(); i++) {
406  std::size_t shift = closureFull[i].size();
407  for(std::size_t j = 0; j < insideClosure[i].size(); j++)
408  closureFull[i].push_back(insideClosure[i][j] + shift);
409  }
410  }
411  }
412 
413  /*
414  void checkClosure(int tag){
415  printf("TYPE = %i\n", tag);
416  const nodalBasis &fs = *nodalBases::find(tag);
417  for(int i = 0; i < fs.closures.size(); ++i){
418  const std::vector<int> &clRef = fs.closures[fs.closureRef[i]];
419  const std::vector<int> &cl = fs.closures[i];
420  const std::vector<int> &clFull = fs.fullClosures[i];
421  printf("i = %i\n", i);
422  for(int j = 0; j < cl.size(); ++j){
423  printf("%3i ", clFull[clRef[j]]);
424  }
425  printf("\n");
426  for(int j = 0; j < cl.size(); ++j){
427  printf("%3i ", cl[j]);
428  }
429  printf("\n");
430  }
431  }
432  */
433 
434  void generateFaceClosureHex(nodalBasis::clCont &closure, int order,
435  bool serendip, const fullMatrix<double> &points)
436  {
437  closure.clear();
438  const nodalBasis &fsFace = *BasisFactory::getNodalBasis(
439  ElementType::getType(TYPE_QUA, order, serendip));
440  for(int iRotate = 0; iRotate < 4; iRotate++) {
441  for(int iSign = 1; iSign >= -1; iSign -= 2) {
442  for(int iFace = 0; iFace < 6; iFace++) {
444  cl.type = fsFace.type;
445  cl.resize(fsFace.points.size1());
446  for(std::size_t iNode = 0; iNode < cl.size(); ++iNode) {
447  double u, v, w;
448  rotateHex(iFace, iRotate, iSign, fsFace.points(iNode, 0),
449  fsFace.points(iNode, 1), u, v, w);
450  cl[iNode] = 0;
451  double D = std::numeric_limits<double>::max();
452  for(int jNode = 0; jNode < points.size1(); ++jNode) {
453  double d = pow2(points(jNode, 0) - u) +
454  pow2(points(jNode, 1) - v) +
455  pow2(points(jNode, 2) - w);
456  if(d < D) {
457  cl[iNode] = jNode;
458  D = d;
459  }
460  }
461  }
462  closure.push_back(cl);
463  }
464  }
465  }
466  }
467 
469  std::vector<int> &closureRef, int order,
470  bool serendip,
471  const fullMatrix<double> &points)
472  {
473  closure.clear();
474  int clId = 0;
475  for(int iRotate = 0; iRotate < 4; iRotate++) {
476  for(int iSign = 1; iSign >= -1; iSign -= 2) {
477  for(int iFace = 0; iFace < 6; iFace++) {
479  cl.resize(points.size1());
480  for(int iNode = 0; iNode < points.size1(); ++iNode) {
481  double u, v, w;
482  rotateHexFull(iFace, iRotate, iSign, points(iNode, 0),
483  points(iNode, 1), points(iNode, 2), u, v, w);
484  int J = 0;
485  double D = std::numeric_limits<double>::max();
486  for(int jNode = 0; jNode < points.size1(); ++jNode) {
487  double d = pow2(points(jNode, 0) - u) +
488  pow2(points(jNode, 1) - v) +
489  pow2(points(jNode, 2) - w);
490  if(d < D) {
491  J = jNode;
492  D = d;
493  }
494  }
495  cl[J] = iNode;
496  }
497  closure.push_back(cl);
498  closureRef.push_back(0);
499  clId++;
500  }
501  }
502  }
503  }
504 
505  void fillInteriorFaceNodes(nodalBasis::closure &closure, int idx, int order,
506  int isTriangle, int start)
507  {
508  // Numbering of nodes in Gmsh is as the following: The first nodes are the
509  // corners. Then follow the nodes on the edges, with an edge being
510  // completely filled before the following is filled. After come the nodes on
511  // faces, with the same strategy. (Eventually, there are the volume nodes.)
512  // Moreover, the numbering of the face interior nodes is coherent with the
513  // numbering of the equivalent 2D element. This explains why this function
514  // is so simple.
515  int nNodes =
516  isTriangle ? (order - 2) * (order - 1) / 2 : (order - 1) * (order - 1);
517  for(int i = 0; i < nNodes; ++i, ++idx, ++start) { closure[idx] = start; }
518  }
519 
520  void reorderFaceClosure(int iSign, int iRotate, nodalBasis::closure &closure,
521  int idx, int order, int isTriangle)
522  {
523  if(order <= 0) return;
524  nodalBasis::closure old = closure;
525  int start = idx;
526 
527  const int nCorner = isTriangle ? 3 : 4;
528  for(int i = 0; i < nCorner; ++i, ++idx) {
529  closure[idx] = old[start + (nCorner + i * iSign + iRotate) % nCorner];
530  }
531 
532  const int &nEdge = nCorner;
533  for(int i = 0; i < nEdge; ++i) {
534  int iOldEdge =
535  (nEdge + i * iSign + iRotate + (iSign == -1 ? -1 : 0)) % nEdge;
536  int startOldEdge = start + nCorner + iOldEdge * (order - 1);
537  if(iSign > 0) {
538  for(int j = startOldEdge; j < startOldEdge + order - 1; ++j, ++idx)
539  closure[idx] = old[j];
540  }
541  else if(iSign < 0) {
542  for(int j = startOldEdge + order - 2; j >= startOldEdge; --j, ++idx)
543  closure[idx] = old[j];
544  }
545  }
546  if(isTriangle && order > 3)
547  reorderFaceClosure(iSign, iRotate, closure, idx, order - 3, isTriangle);
548  else if(!isTriangle && order > 2)
549  reorderFaceClosure(iSign, iRotate, closure, idx, order - 2, isTriangle);
550  }
551 
552  void getFaceClosurePrism(int iFace, int iSign, int iRotate,
553  nodalBasis::closure &closure, int order)
554  {
555  closure.clear();
556  bool isTriangle = iFace < 2;
557  if(isTriangle && iRotate > 2) return;
558  closure.type =
559  ElementType::getType(isTriangle ? TYPE_TRI : TYPE_QUA, order);
560 
561  int nNodes =
562  isTriangle ? (order + 1) * (order + 2) / 2 : (order + 1) * (order + 1);
563  closure.resize(nNodes);
564  if(order == 0) {
565  closure[0] = 0;
566  return;
567  }
568 
569  // map edge number to the nodes number
570  int *edge2nodes[9];
571  int n = 6;
572  for(int i = 0; i < 9; ++i) {
573  edge2nodes[i] = new int[order - 1];
574  for(int k = 0; k < order - 1; ++k, ++n) edge2nodes[i][k] = n;
575  }
576 
577  // fill corner node number
578  const int nCorner = isTriangle ? 3 : 4;
579  for(int i = 0; i < nCorner; ++i) {
580  closure[i] = MPrism::faces_prism(iFace, i);
581  }
582 
583  // fill high-order nodes number
584  if(order > 1) {
585  int idx = nCorner;
586  const int &nEdge = nCorner;
587 
588  // fill edge nodes number
589  for(int i = 0; i < nEdge; ++i) {
590  int edge = MPrism::faceClosureEdge2edge(iFace, i);
591  if(edge > 0) {
592  edge = edge - 1;
593  for(int k = 0; k < order - 1; ++k, ++idx) {
594  closure[idx] = edge2nodes[edge][k];
595  }
596  }
597  else if(edge < 0) {
598  edge = -edge - 1;
599  for(int k = order - 2; k >= 0; --k, ++idx) {
600  closure[idx] = edge2nodes[edge][k];
601  }
602  }
603  }
604  for(int i = 0; i < 9; ++i) delete edge2nodes[i];
605 
606  // Numbering of nodes inside the face start at
607  int start = 6 + 9 * (order - 1) +
608  std::min(iFace, 2) * (order - 2) * (order - 1) / 2 +
609  std::max(iFace - 2, 0) * (order - 1) * (order - 1);
610 
611  // fill interior nodes number
612  fillInteriorFaceNodes(closure, idx, order, isTriangle, start);
613  }
614 
615  reorderFaceClosure(iSign, iRotate, closure, 0, order, isTriangle);
616  }
617 
619  {
620  closure.clear();
621  for(int iRotate = 0; iRotate < 4; iRotate++) {
622  for(int iSign = 1; iSign >= -1; iSign -= 2) {
623  for(int iFace = 0; iFace < 5; iFace++) {
624  nodalBasis::closure closure_face;
625  getFaceClosurePrism(iFace, iSign, iRotate, closure_face, order);
626  closure.push_back(closure_face);
627  }
628  }
629  }
630  }
631 
633  std::vector<int> &closureRef, int order)
634  {
635  nodalBasis::clCont closure;
636  closureFull.clear();
637  closureFull.resize(40);
638  closureRef.resize(40);
639  generateFaceClosurePrism(closure, 1);
640  int ref3 = -1, ref4a = -1, ref4b = -1;
641  for(std::size_t i = 0; i < closure.size(); i++) {
642  std::vector<int> &clFull = closureFull[i];
643  std::vector<int> &cl = closure[i];
644  if(cl.size() == 0) continue;
645  clFull.resize(6, -1);
646  int &ref = cl.size() == 3 ? ref3 :
647  (cl[0] / 3 + cl[1] / 3) % 2 ? ref4b :
648  ref4a;
649  if(ref == -1) ref = i;
650  closureRef[i] = ref;
651  for(std::size_t j = 0; j < cl.size(); j++)
652  clFull[closure[ref][j]] = cl[j];
653  for(int j = 0; j < 6; j++) {
654  if(clFull[j] == -1) {
655  int k = ((j / 3) + 1) % 2 * 3;
656  int sum = (clFull[k + (j + 1) % 3] + clFull[k + (j + 2) % 3]);
657  clFull[j] = ((sum / 6 + 1) % 2) * 3 + (12 - sum) % 3;
658  }
659  }
660  }
661  static const int edges[] = {0, 1, 0, 2, 0, 3, 1, 2, 1, 4,
662  2, 5, 3, 4, 3, 5, 4, 5, -1};
663  addEdgeNodes(closureFull, edges, order);
664  if(order < 2) return;
665  // face center nodes for p2 prism
666  static const int faces[5][4] = {
667  {0, 2, 1, -1}, {3, 4, 5, -1}, {0, 1, 4, 3}, {0, 3, 5, 2}, {1, 2, 5, 4}};
668 
669  if(order == 2) {
670  int nextFaceNode = 15;
671  int numFaces = 5;
672  int numFaceNodes = 4;
673  std::map<int, int> nodeSum2Face;
674  for(int iFace = 0; iFace < numFaces; iFace++) {
675  int nodeSum = 0;
676  for(int iNode = 0; iNode < numFaceNodes; iNode++) {
677  nodeSum += faces[iFace][iNode];
678  }
679  nodeSum2Face[nodeSum] = iFace;
680  }
681  for(std::size_t i = 0; i < closureFull.size(); i++) {
682  if(closureFull[i].empty()) continue;
683  for(int iFace = 0; iFace < numFaces; iFace++) {
684  int nodeSum = 0;
685  for(int iNode = 0; iNode < numFaceNodes; iNode++)
686  nodeSum += faces[iFace][iNode] < 0 ?
687  faces[iFace][iNode] :
688  closureFull[i][faces[iFace][iNode]];
689  auto it = nodeSum2Face.find(nodeSum);
690  if(it == nodeSum2Face.end()) Msg::Error("Prism face not found");
691  int mappedFaceId = it->second;
692  if(mappedFaceId > 1) {
693  closureFull[i].push_back(nextFaceNode + mappedFaceId - 2);
694  }
695  }
696  }
697  }
698  else {
699  Msg::Error("FaceClosureFull not implemented for prisms of order %d",
700  order);
701  }
702  }
703 
704  void generateFaceClosurePyr(nodalBasis::clCont &closure, int order,
705  bool serendip, const fullMatrix<double> &points)
706  {
707  closure.clear();
708  const int typeTri = ElementType::getType(TYPE_TRI, order, serendip);
709  const int typeQua = ElementType::getType(TYPE_QUA, order, serendip);
710  const nodalBasis *fsFaceTri = BasisFactory::getNodalBasis(typeTri);
711  const nodalBasis *fsFaceQua = BasisFactory::getNodalBasis(typeQua);
712 
713  for(int iRotate = 0; iRotate < 4; iRotate++) {
714  for(int iSign = 1; iSign >= -1; iSign -= 2) {
715  for(int iFace = 0; iFace < 5; iFace++) {
716  const nodalBasis *fsFace;
717  if(iFace < 4)
718  fsFace = fsFaceTri;
719  else
720  fsFace = fsFaceQua;
722  cl.type = fsFace->type;
723  cl.resize(fsFace->points.size1());
724  for(std::size_t iNode = 0; iNode < cl.size(); ++iNode) {
725  double u, v, w;
726  rotatePyr(iFace, iRotate, iSign, fsFace->points(iNode, 0),
727  fsFace->points(iNode, 1), u, v, w);
728  cl[iNode] = 0;
729  double D = std::numeric_limits<double>::max();
730  for(int jNode = 0; jNode < points.size1(); ++jNode) {
731  double d = pow2(points(jNode, 0) - u) +
732  pow2(points(jNode, 1) - v) +
733  pow2(points(jNode, 2) - w);
734  if(d < D) {
735  cl[iNode] = jNode;
736  D = d;
737  }
738  }
739  }
740  closure.push_back(cl);
741  }
742  }
743  }
744  }
745 
746  void generate2dEdgeClosure(nodalBasis::clCont &closure, int order,
747  int nNod = 3)
748  {
749  closure.clear();
750  closure.resize(2 * nNod);
751  for(int j = 0; j < nNod; j++) {
752  closure[j].push_back(j);
753  closure[j].push_back((j + 1) % nNod);
754  closure[nNod + j].push_back((j + 1) % nNod);
755  closure[nNod + j].push_back(j);
756  for(int i = 0; i < order - 1; i++) {
757  closure[j].push_back(nNod + (order - 1) * j + i);
758  closure[nNod + j].push_back(nNod + (order - 1) * (j + 1) - i - 1);
759  }
760  closure[j].type = closure[nNod + j].type =
762  }
763  }
764 
766  {
767  closure.clear();
768  closure.resize(nb);
769  for(int i = 0; i < nb; i++) {
770  closure[i].push_back(0);
771  closure[i].type = MSH_PNT;
772  }
773  }
774 } // namespace ClosureGen
775 
777 {
778  using namespace ClosureGen;
779  type = tag;
784 
785  switch(parentType) {
786  case TYPE_PNT:
787  numFaces = 1;
789  break;
790  case TYPE_LIN:
791  numFaces = 2;
795  break;
796  case TYPE_TRI:
797  numFaces = 3;
799  if(order == 0) {
802  closureRef.resize(6, 0);
803  }
804  else {
807  }
808  break;
809  case TYPE_QUA:
810  numFaces = 4;
812  if(order == 0) {
815  closureRef.resize(8, 0);
816  }
817  else {
820  }
821  break;
822  case TYPE_TET:
823  numFaces = 4;
825  if(order == 0) {
828  closureRef.resize(24, 0);
829  }
830  else {
833  }
834  break;
835  case TYPE_PRI:
836  numFaces = 5;
838  if(order == 0) {
841  closureRef.resize(48, 0);
842  }
843  else {
846  }
847  break;
848  case TYPE_HEX:
849  numFaces = 6;
853  points);
854  break;
855  case TYPE_PYR:
856  numFaces = 5;
859  break;
860  }
861 }
862 
864 {
865  int numBubble = -1;
866  switch(parentType) {
867  case TYPE_PNT: numBubble = 0; break;
868  case TYPE_LIN: numBubble = ElementType::getNumVertices(type) - 2; break;
869  case TYPE_TRI:
870  if(serendip) { numBubble = 0; }
871  else {
872  numBubble = (order - 1) * (order - 2) / 2;
873  }
874  break;
875  case TYPE_QUA:
876  if(serendip) { numBubble = 0; }
877  else {
878  numBubble = (order - 1) * (order - 1);
879  }
880  break;
881  case TYPE_TET:
882  if(serendip) { numBubble = 0; }
883  else {
884  numBubble = ((order - 1) * (order - 2) * (order - 3)) / 6;
885  }
886  break;
887  case TYPE_PRI:
888  if(serendip) { numBubble = 0; }
889  else {
890  numBubble = (order - 1) * (((order - 1) - 1) * (order - 1) / 2);
891  }
892  break;
893  case TYPE_HEX:
894  if(serendip) { numBubble = 0; }
895  else {
896  numBubble = (order - 1) * (order - 1) * (order - 1);
897  }
898  break;
899  case TYPE_PYR:
900  if(serendip) { numBubble = 0; }
901  else {
902  numBubble = (order - 2) * ((order - 2) + 1) * (2 * (order - 2) + 1) / 6;
903  }
904  break;
905  }
906 
907  return numBubble;
908 }
909 
912  int elementType) const
913 {
914  if(elementType != -1 && elementType != type) {
915  std::cout << "Incorrect element type " << std::endl;
916  return false;
917  }
918  if(nodes.size1() != points.size1()) return false;
919 
920  projection.resize(nodes.size1(), points.size1());
921  f(nodes, projection);
922 
923  projection.invertInPlace();
924  // projection.transposeInPlace();
925  return true;
926 }
927 
929  int elementType) const
930 {
931  if(nodes.size1() != points.size1()) {
932  std::cout << "Non-matching node counts " << nodes.size1() << " vs "
933  << points.size1() << std::endl;
934  return false;
935  }
936 
937  double tol = 1e-10;
938 
939  fullMatrix<double> tfo;
940  if(!forwardTransformation(nodes, tfo, elementType)) {
941  std::cout << "Could not find forward transformation " << std::endl;
942  return false;
943  }
944 
945  // tfo.print("Projection matrix","%1.f");
946 
947  for(int i = 0; i < nodes.size1(); i++) {
948  int idx = -1;
949  int nbOnes = 0;
950  int nbZeroes = 0;
951  for(int j = 0; j < nodes.size1(); j++) {
952  if(fabs(tfo(i, j) - 1.0) < tol) {
953  idx = j;
954  nbOnes++;
955  }
956  if(fabs(tfo(i, j)) < tol) { nbZeroes++; }
957  }
958  if(nbOnes != 1) return false;
959  if(nbZeroes != nodes.size1() - 1) return false;
960  renum[i] = idx;
961  }
962 
963  // for (int i=0;i<nodes.size1();i++) {
964  // std::cout << i << " -> " << renum[i] << std::endl;
965  // }
966 
967  return renum;
968 }
nodalBasis::forwardRenumbering
bool forwardRenumbering(const fullMatrix< double > &otherPoints, int *renum, int elemenType=-1) const
Definition: nodalBasis.cpp:928
ClosureGen::rotateHexFull
void rotateHexFull(int iFace, int iRot, int iSign, double uI, double vI, double wI, double &uO, double &vO, double &wO)
Definition: nodalBasis.cpp:64
ClosureGen::generateFaceClosureTet
void generateFaceClosureTet(nodalBasis::clCont &closure, int order)
Definition: nodalBasis.cpp:320
gmshGeneratePointsTriangle
fullMatrix< double > gmshGeneratePointsTriangle(int order, bool serendip)
Definition: pointsGenerators.cpp:51
D
#define D
Definition: DefaultOptions.h:24
MPrism::faces_prism
static int faces_prism(const int face, const int vert)
Definition: MPrism.h:188
nodalBasis::clCont
std::vector< closure > clCont
Definition: nodalBasis.h:67
ClosureGen::addEdgeNodes
void addEdgeNodes(nodalBasis::clCont &closureFull, const int *edges, int order)
Definition: nodalBasis.cpp:291
nodalBasis::closureRef
std::vector< int > closureRef
Definition: nodalBasis.h:69
nodalBasis::points
fullMatrix< double > points
Definition: nodalBasis.h:16
gmshGeneratePointsPrism
fullMatrix< double > gmshGeneratePointsPrism(int order, bool serendip)
Definition: pointsGenerators.cpp:85
ClosureGen::generateFaceClosurePyr
void generateFaceClosurePyr(nodalBasis::clCont &closure, int order, bool serendip, const fullMatrix< double > &points)
Definition: nodalBasis.cpp:704
MSH_PNT
#define MSH_PNT
Definition: GmshDefines.h:94
TYPE_LIN
#define TYPE_LIN
Definition: GmshDefines.h:65
ClosureGen::generateFaceClosureHex
void generateFaceClosureHex(nodalBasis::clCont &closure, int order, bool serendip, const fullMatrix< double > &points)
Definition: nodalBasis.cpp:434
gmshGeneratePointsTetrahedron
fullMatrix< double > gmshGeneratePointsTetrahedron(int order, bool serendip)
Definition: pointsGenerators.cpp:68
gmshGeneratePointsQuadrangle
fullMatrix< double > gmshGeneratePointsQuadrangle(int order, bool serendip)
Definition: pointsGenerators.cpp:59
nodalBasis.h
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
nodalBasis::numFaces
int numFaces
Definition: nodalBasis.h:14
TYPE_PNT
#define TYPE_PNT
Definition: GmshDefines.h:64
ElementType::getSerendipity
int getSerendipity(int type)
Definition: ElementType.cpp:598
projection
static double projection(SPoint3 &p1, SPoint3 &p2, SPoint3 &q, SPoint3 &result)
Definition: hausdorffDistance.cpp:29
TYPE_TRI
#define TYPE_TRI
Definition: GmshDefines.h:66
ClosureGen::pow2
double pow2(double x)
Definition: nodalBasis.cpp:15
MPrism::faceClosureEdge2edge
static int faceClosureEdge2edge(const int face, const int edge)
Definition: MPrism.h:205
ClosureGen::generate2dEdgeClosureFull
void generate2dEdgeClosureFull(nodalBasis::clCont &closure, std::vector< int > &closureRef, int order, int nNod, bool serendip)
Definition: nodalBasis.cpp:251
nodalBasis::parentType
int parentType
Definition: nodalBasis.h:14
ClosureGen::generateFaceClosurePrism
void generateFaceClosurePrism(nodalBasis::clCont &closure, int order)
Definition: nodalBasis.cpp:618
nodalBasis::forwardTransformation
bool forwardTransformation(const fullMatrix< double > &otherPoints, fullMatrix< double > &projection, int elementType=-1) const
Definition: nodalBasis.cpp:910
ClosureGen::generateFaceClosureHexFull
void generateFaceClosureHexFull(nodalBasis::clCont &closure, std::vector< int > &closureRef, int order, bool serendip, const fullMatrix< double > &points)
Definition: nodalBasis.cpp:468
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
nodalBasis::closure::type
int type
Definition: nodalBasis.h:65
ClosureGen::getFaceClosurePrism
void getFaceClosurePrism(int iFace, int iSign, int iRotate, nodalBasis::closure &closure, int order)
Definition: nodalBasis.cpp:552
nodalBasis::type
int type
Definition: nodalBasis.h:14
TYPE_PRI
#define TYPE_PRI
Definition: GmshDefines.h:70
nodalBasis::serendip
bool serendip
Definition: nodalBasis.h:15
ClosureGen
Definition: nodalBasis.cpp:14
fullMatrix< double >
nodalBasis::order
int order
Definition: nodalBasis.h:14
BasisFactory::getNodalBasis
static const nodalBasis * getNodalBasis(int tag)
Definition: BasisFactory.cpp:23
ClosureGen::rotateHex
void rotateHex(int iFace, int iRot, int iSign, double uI, double vI, double &uO, double &vO, double &wO)
Definition: nodalBasis.cpp:17
nodalBasis::f
virtual void f(double u, double v, double w, double *sf) const =0
ClosureGen::generateFaceClosureTetFull
void generateFaceClosureTetFull(nodalBasis::clCont &closureFull, std::vector< int > &closureRef, int order, bool serendip)
Definition: nodalBasis.cpp:334
ElementType::getType
int getType(int parentType, int order, bool serendip=false)
Definition: ElementType.cpp:757
ClosureGen::fillInteriorFaceNodes
void fillInteriorFaceNodes(nodalBasis::closure &closure, int idx, int order, int isTriangle, int start)
Definition: nodalBasis.cpp:505
ClosureGen::generateFaceClosurePrismFull
void generateFaceClosurePrismFull(nodalBasis::clCont &closureFull, std::vector< int > &closureRef, int order)
Definition: nodalBasis.cpp:632
ClosureGen::rotatePyr
void rotatePyr(int iFace, int iRot, int iSign, double uI, double vI, double &uO, double &vO, double &wO)
Definition: nodalBasis.cpp:111
nodalBasis::getNumBubbleShapeFunctions
int getNumBubbleShapeFunctions() const
Definition: nodalBasis.cpp:863
nodalBasis::nodalBasis
nodalBasis()
Definition: nodalBasis.h:18
ClosureGen::generate1dVertexClosureFull
void generate1dVertexClosureFull(nodalBasis::clCont &closure, std::vector< int > &closureRef, int order)
Definition: nodalBasis.cpp:163
nodalBasis::closure
Definition: nodalBasis.h:63
gmshGeneratePointsHexahedron
fullMatrix< double > gmshGeneratePointsHexahedron(int order, bool serendip)
Definition: pointsGenerators.cpp:76
nodalBasis::dimension
int dimension
Definition: nodalBasis.h:14
gmshGeneratePointsPyramid
fullMatrix< double > gmshGeneratePointsPyramid(int order, bool serendip)
Definition: pointsGenerators.cpp:98
TYPE_PYR
#define TYPE_PYR
Definition: GmshDefines.h:69
ClosureGen::generateClosureOrder0
void generateClosureOrder0(nodalBasis::clCont &closure, int nb)
Definition: nodalBasis.cpp:765
TYPE_QUA
#define TYPE_QUA
Definition: GmshDefines.h:67
ClosureGen::getFaceClosureTet
void getFaceClosureTet(int iFace, int iSign, int iRotate, nodalBasis::closure &closure, int order)
Definition: nodalBasis.cpp:183
nodalBasis
Definition: nodalBasis.h:12
ElementType::getDimension
int getDimension(int type)
Definition: ElementType.cpp:297
nodalBasis::closures
clCont closures
Definition: nodalBasis.h:68
ClosureGen::generate2dEdgeClosure
void generate2dEdgeClosure(nodalBasis::clCont &closure, int order, int nNod=3)
Definition: nodalBasis.cpp:746
fullMatrix::size1
int size1() const
Definition: fullMatrix.h:274
ElementType::getOrder
int getOrder(int type)
Definition: ElementType.cpp:158
nodalBasis::fullClosures
clCont fullClosures
Definition: nodalBasis.h:68
TYPE_HEX
#define TYPE_HEX
Definition: GmshDefines.h:71
MPrism.h
TYPE_TET
#define TYPE_TET
Definition: GmshDefines.h:68
ElementType::getNumVertices
int getNumVertices(int type)
Definition: ElementType.cpp:456
ClosureGen::generate1dVertexClosure
void generate1dVertexClosure(nodalBasis::clCont &closure, int order)
Definition: nodalBasis.cpp:153
pointsGenerators.h
gmshGeneratePointsLine
fullMatrix< double > gmshGeneratePointsLine(int order)
Definition: pointsGenerators.cpp:42
ClosureGen::reorderFaceClosure
void reorderFaceClosure(int iSign, int iRotate, nodalBasis::closure &closure, int idx, int order, int isTriangle)
Definition: nodalBasis.cpp:520
ElementType::getParentType
int getParentType(int type)
Definition: ElementType.cpp:10
BasisFactory.h
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165