Flow123d  JS_before_hm-978-gfd4e3d8
ref_element.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file ref_element.cc
15  * @brief Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc.
16  * @author Jan Stebel
17  */
18 
19 #include "system/global_defs.h"
20 #include "system/system.hh"
21 #include "mesh/ref_element.hh"
22 
23 
24 
25 using namespace arma;
26 using namespace std;
27 
28 template<std::size_t n>
30  std::vector< std::vector<unsigned int> > vec(array_vec.size());
31  for(unsigned int i=0; i<array_vec.size(); i++)
32  for(unsigned int j=0;j<n; j++)
33  vec[i].push_back(array_vec[i][j]);
34  return vec;
35 }
36 
37 
38 // template<unsigned int n>
39 // std::vector< std::vector<unsigned int> > _array_to_vec( const unsigned int array[][n], unsigned int m) {
40 // std::vector< std::vector<unsigned int> > vec(m);
41 // for(unsigned int i=0; i<m; i++)
42 // for(unsigned int j=0;j<n; j++)
43 // vec[i].push_back(array[i][j]);
44 // return vec;
45 // }
46 
47 
48 
49 
51  = { {0,1} };
52 
54  = { {0,1},
55  {0,2},
56  {1,2}};
57 
59  = { {0,1}, //0
60  {0,2}, //1
61  {0,3}, //2 <-3 (fixed order)
62  {1,2}, //3 <-2
63  {1,3}, //4
64  {2,3}}; //5
65 
66 
68  = { {0},
69  {0}};
70 
72  = { {1,0},
73  {0,2},
74  {2,1}};
75 
76 // Order clockwise looking over the vertex to center; smallest index first
78  = { {0,1,2},
79  {0,4,3},
80  {1,3,5},
81  {2,5,4}};
82 
83 
84 
85 // Lexicographic order.
87  = { { 0, 1, 2 },
88  { 0, 1, 3 },
89  { 0, 2, 3 },
90  { 1, 2, 3 }};
91 
92 // Order clockwise, faces opposite to the lines from node_lines.
94  = { { 2, 1, 0 },
95  { 3, 0, 1 },
96  { 3, 2, 0 },
97  { 3, 1, 2 }};
98 
99 // faces ordered clock wise with respect to edge shifted to center of tetrahedron
101  = { {0,1},
102  {2,0},
103  {1,2},
104  {0,3},
105  {3,1},
106  {2,3}};
107 
108 
110  = { {0,1,3},
111  {0,2,4},
112  {1,2,5},
113  {3,4,5}};
114 
115 
118 
121 
123  RefElement<2>::side_permutations = { { 0, 1 }, { 1, 0 } };
124 
127  { 0, 1, 2 },
128  { 0, 2, 1 },
129  { 1, 0, 2 },
130  { 1, 2, 0 },
131  { 2, 0, 1 },
132  { 2, 1, 0 }
133  };
134 
135 // template<> const unsigned int RefElement<0>::side_permutations[][n_nodes_per_side] = { };
136 
137 // template<> const unsigned int RefElement<1>::side_permutations[][n_nodes_per_side] = { { 0 } };
138 
139 // template<> const unsigned int RefElement<2>::side_permutations[][n_nodes_per_side] = { { 0, 1 }, { 1, 0 } };
140 
141 // template<> const unsigned int RefElement<3>::side_permutations[][n_nodes_per_side] = {
142 // { 0, 1, 2 },
143 // { 0, 2, 1 },
144 // { 1, 0, 2 },
145 // { 1, 2, 0 },
146 // { 2, 0, 1 },
147 // { 2, 1, 0 }
148 // };
149 
150 
152  {(1 << 1)} //node 0
153 };
154 
155 
157  {(1 << 1), //node 0
158  (1 << 0)}, //node 1
159  {0, //the element
160  0}
161 };
162 
163 
165  {(1 << 1) | (1 << 2), //node 0
166  (1 << 0) | (1 << 2), //node 1
167  (1 << 0) | (1 << 1)}, //node 2
168  {(1 << 2), //line 0
169  (1 << 1), //line 1
170  (1 << 0)}, //line 2
171  {0, //the element
172  0,
173  0}
174 };
175 
177  {(1 << 1) | (1 << 2) | (1 << 3), //node 0
178  (1 << 0) | (1 << 2) | (1 << 3), //node 1
179  (1 << 0) | (1 << 1) | (1 << 3), //node 2
180  (1 << 0) | (1 << 1) | (1 << 2), //node 3
181  0,
182  0},
183  {(1 << 2) | (1 << 3), //line 0
184  (1 << 1) | (1 << 3), //line 1
185  (1 << 1) | (1 << 2), //line 2
186  (1 << 0) | (1 << 3), //line 3
187  (1 << 0) | (1 << 2), //line 4
188  (1 << 0) | (1 << 1)}, //line 5
189  {1 << 3, //side 0
190  1 << 2, //side 1
191  1 << 1, //side 2
192  1 << 0, //side 3
193  0,
194  0},
195  {0, //the element
196  0,
197  0,
198  0,
199  0,
200  0}
201 };
202 
203 
204 
205 
206 // template<> const unsigned int RefElement<1>::side_nodes[][1] = {
207 // { 0 },
208 // { 1 }
209 // };
210 //
211 // template<> const unsigned int RefElement<2>::side_nodes[][2] = {
212 // { 0, 1 },
213 // { 0, 2 },
214 // { 1, 2 }
215 // };
216 //
217 // template<> const unsigned int RefElement<3>::side_nodes[][3] = {
218 // { 0, 1, 2 },
219 // { 0, 1, 3 },
220 // { 0, 2, 3 },
221 // { 1, 2, 3 }
222 // };
223 //
224 //
225 //
226 // template<> const unsigned int RefElement<3>::side_lines[][3] = {
227 // {0,1,2},
228 // {0,3,4},
229 // {1,3,5},
230 // {2,4,5}
231 // };
232 //
233 //
234 // template<> const unsigned int RefElement<1>::line_nodes[][2] = {
235 // {0,1}
236 // };
237 //
238 // template<> const unsigned int RefElement<2>::line_nodes[][2] = {
239 // {0,1},
240 // {0,2},
241 // {1,2}
242 // };
243 //
244 // template<> const unsigned int RefElement<3>::line_nodes[][2] = {
245 // {0,1},
246 // {0,2},
247 // {1,2},
248 // {0,3},
249 // {1,3},
250 // {2,3}
251 // };
252 //
253 //
254 // /**
255 // * Indexes of sides for each line - with right orientation
256 // */
257 //
258 // template<> const unsigned int RefElement<3>::line_sides[][2] = {
259 // {0,1},
260 // {2,0},
261 // {0,3},
262 // {1,2},
263 // {3,1},
264 // {2,3}
265 // };
266 //
267 // /**
268 // * Indexes of sides for each line - for Simplex<2>, with right orientation
269 // */
270 // template<> const unsigned int RefElement<2>::line_sides[][2] = {
271 // {1,0},
272 // {0,2},
273 // {2,1}
274 // };
275 
276 
277 // 0: nodes of nodes
278 // 1: nodes of lines
279 // 2: nodes of sides
280 // 3: nodes of tetrahedron
282  { {0} }
283 };
284 
286  { {0}, {1} },
287  _array_to_vec(line_nodes_)
288 };
289 
291  { {0}, {1}, {2} },
292  _array_to_vec(line_nodes_),
293  { {0,1,2} }
294 };
295 
297  { {0}, {1}, {2}, {3} },
298  _array_to_vec(line_nodes_),
299  _array_to_vec(side_nodes_),
300  { {0,1,2,3} }
301 };
302 
303 
304 template<unsigned int dim>
306 {
307  ASSERT_EQ_DBG(lp.n_rows, dim);
308  BaryPoint bp;
309  bp.rows(1, dim ) = lp;
310  bp( 0 ) = 1.0 - arma::sum(lp);
311  return bp;
312 
313  // new armadillo
314  // return arma::join_col( arma::vec::fixed<1>( { 1.0 - arma::sum( local )} ), local);
315 
316 }
317 
318 template<unsigned int dim>
320 {
321  ASSERT_EQ_DBG(bp.n_rows, dim+1);
322  LocalPoint lp = bp.rows(1, dim);
323  return lp;
324 }
325 
326 template<unsigned int dim>
327 inline unsigned int RefElement<dim>::oposite_node(unsigned int sid)
328 {
329  return n_sides - sid - 1;
330 }
331 
332 
333 template<unsigned int dim>
334 unsigned int RefElement<dim>::normal_orientation(unsigned int sid)
335 {
336  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
337 
338  return sid % 2;
339 }
340 
341 
342 template<>
343 vec::fixed<1> RefElement<1>::normal_vector(unsigned int sid)
344 {
345  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
346 
347  return node_coords(sid) - node_coords(1-sid);
348 }
349 
350 template<>
351 vec::fixed<2> RefElement<2>::normal_vector(unsigned int sid)
352 {
353  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
354  vec::fixed<2> barycenter, bar_side, n, t;
355 
356  // tangent vector along line
357  t = node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]);
358  // barycenter coordinates
359  barycenter.fill(1./3);
360  // vector from barycenter to the side
361  bar_side = node_coords(line_nodes_[sid][0]) - barycenter;
362  // normal vector to side (modulo sign)
363  n(0) = -t(1);
364  n(1) = t(0);
365  n /= norm(n,2);
366  // check sign of normal vector
367  if (dot(n,bar_side) < 0) n *= -1;
368 
369  return n;
370 }
371 
372 template<>
373 vec::fixed<3> RefElement<3>::normal_vector(unsigned int sid)
374 {
375  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
376  vec::fixed<3> barycenter, bar_side, n, t1, t2;
377 
378  // tangent vectors of side
379  t1 = node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]);
380  t2 = node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0]);
381  // baryucenter coordinates
382  barycenter.fill(0.25);
383  // vector from barycenter to the side
384  bar_side = node_coords(side_nodes_[sid][0]) - barycenter;
385  // normal vector (modulo sign)
386  n = cross(t1,t2);
387  n /= norm(n,2);
388  // check sign of normal vector
389  if (dot(n,bar_side) < 0) n = -n;
390 
391  return n;
392 }
393 
394 
395 
396 template<unsigned int dim>
397 auto RefElement<dim>::barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face) -> FaceBaryPoint
398 {
399  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
400  FaceBaryPoint face_barycentric;
401  for(unsigned int i=0; i < dim; i++) {
402 // unsigned int i_sub_node = (i+1)%dim;
403 // unsigned int i_bary = (dim + side_nodes_[i_face][i_sub_node])%(dim+1);
404  unsigned int i_bary = interact_<0,dim-1>(i_face)[i];
405  face_barycentric[i] = barycentric[ i_bary ];
406  }
407  return face_barycentric;
408 }
409 
410 
411 template<unsigned int dim>
412 std::pair<unsigned int, unsigned int> RefElement<dim>::zeros_positions(const BaryPoint &barycentric,
413  double tolerance)
414 {
415  unsigned int zeros = 0;
416  unsigned int n_zeros = 0;
417  for(unsigned int i=0; i < dim+1; i++){
418  if(std::fabs(barycentric[i]) < tolerance)
419  {
420  zeros = zeros | (1 << i);
421  n_zeros++;
422  }
423  }
424 
425  return std::make_pair(n_zeros, zeros);
426 }
427 
428 
429 template<>
430 auto RefElement<0>::clip(const BaryPoint &barycentric) -> BaryPoint
431 {
432  return barycentric;
433 }
434 
435 template<unsigned int dim>
436 auto RefElement<dim>::make_bary_unit_vec()->BarycentricUnitVec
437 {
438  std::vector<arma::vec::fixed<dim+1> > bary_unit_vec(dim+1, arma::zeros(dim+1));
439  for(unsigned int i=0; i<dim; i++) {
440  bary_unit_vec[i][i] = 1.0;
441  bary_unit_vec[i][dim] = -1.0;
442  bary_unit_vec[dim][i] = -1.0 / dim;
443  }
444  bary_unit_vec[dim][dim] = 1.0;
445  return bary_unit_vec;
446 }
447 
448 
449 template<unsigned int dim>
450 auto RefElement<dim>::clip(const BaryPoint &barycentric) -> BaryPoint
451 {
452  static BarycentricUnitVec bary_unit_vec = make_bary_unit_vec();
453  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
454  for(unsigned int i_bary=0; i_bary < dim +1; i_bary ++) {
455  if (barycentric[i_bary] < 0.0) {
456  // index of barycentric coord that is constant on the face i_side
457  // as we use barycentric coords starting with local coordinates:
458  // TODO: rather work only with local coords and/or with canonical barycentric coords
459  unsigned int i_side = (dim - i_bary);
460  // project to face
461  arma::vec projection_to_face(dim+1);
462  //barycentric.print(cout, "input");
463  //cout << "is: " << i_side << endl;
464  //cout << "ibary: " << i_bary << endl;
465  //bary_unit_vec[i_bary].print(cout, "normal");
466  //barycentric.subvec(0, dim-1).print(cout, "bary sub");
467  projection_to_face = barycentric - barycentric[i_bary]*bary_unit_vec[i_bary];
468  //projection_to_face(dim) = 1.0 - arma::sum(projection_to_face.subvec(0, dim-1));
469  //projection_to_face.print(cout, "projection");
470  auto bary_on_face = barycentric_on_face(projection_to_face, i_side);
471  //bary_on_face.print(cout, "b on f");
472  auto sub_clip = RefElement<dim-1>::clip(bary_on_face);
473  //sub_clip.print(cout, "sub clip");
474  return interpolate<dim-1>(sub_clip, i_side);
475  }
476  }
477  return barycentric;
478 
479 }
480 
481 
482 
483 template<unsigned int dim>
484 auto RefElement<dim>::centers_of_subelements(unsigned int sub_dim)->CentersList
485 {
487  if (list.size() == 0) {
488  list.resize(dim+1);
489  for(unsigned int sdim=0; sdim < dim+1; sdim++) {
490  // Temporary solution until we have unified interface to
491  // the internal indexing.
492  // We use the fact that numbering of subelements goes as numbering of
493  // k combinations over nodes.
494 // std::vector<unsigned int> subel_comb(sdim+2);
495  for(auto &sub_el_nodes : nodes_of_subelements[sdim]) {
496  ASSERT_EQ_DBG(sub_el_nodes.size(), sdim+1);
497  LocalPoint center = arma::zeros(dim);
498  for( unsigned int i_node : sub_el_nodes)
499  center+=node_coords( i_node );
500  center/=(sdim+1);
501  list[sdim].push_back(center);
502  }
503  }
504  }
505 
506  ASSERT_LE_DBG(sub_dim, dim);
507  return list[sub_dim];
508 }
509 
510 
511 template<>
512 double RefElement<1>::side_measure(unsigned int sid)
513 {
514  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
515 
516  return 1;
517 }
518 
519 
520 template<>
521 double RefElement<2>::side_measure(unsigned int sid)
522 {
523  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
524 
525  return norm(node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]),2);
526 }
527 
528 
529 template<>
530 double RefElement<3>::side_measure(unsigned int sid)
531 {
532  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
533 
534  return 0.5*norm(cross(node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]),
535  node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0])),2);
536 }
537 
538 
539 
540 template <>
541 unsigned int RefElement<3>::line_between_faces(unsigned int f1, unsigned int f2) {
542  unsigned int i,j;
543  i=j=0;
544  while (side_lines_[f1][i] != side_lines_[f2][j])
545  if (side_lines_[f1][i] < side_lines_[f2][j]) i++;
546  else j++;
547  return side_lines_[f1][i];
548 }
549 
550 
551 template<unsigned int dim>
552 unsigned int RefElement<dim>::permutation_index(unsigned int p[n_nodes_per_side])
553 {
554  unsigned int index;
555  for (index = 0; index < n_side_permutations; index++)
556  if (equal(p, p + n_nodes_per_side, side_permutations[index].data()))
557  return index;
558 
559  xprintf(PrgErr, "Side permutation not found.\n");
560 
561  // The following line is present in order to suppress compilers warning
562  // about missing return value.
563  return 0;
564 }
565 
566 
567 /**
568  * Basic line interpolation
569  */
570 template<unsigned int dim>
572  arma::vec::fixed<dim+1> first_coords,
573  arma::vec::fixed<dim+1> second_coords,
574  double first_theta, double second_theta, double theta){
575 
576  arma::vec::fixed<dim+1> bary_interpolated_coords;
577  bary_interpolated_coords = ((theta - first_theta) * second_coords + (second_theta - theta) * first_coords)
578  /(second_theta - first_theta);
579  return bary_interpolated_coords;
580 }
581 
582 template class RefElement<0>;
583 template class RefElement<1>;
584 template class RefElement<2>;
585 template class RefElement<3>;
586 
587 
Armor::ArmaVec< double, dim > FaceBaryPoint
Definition: ref_element.hh:174
static LocalPoint normal_vector(unsigned int sid)
#define ASSERT_EQ_DBG(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:332
ArmaVec< double, N > vec
Definition: armor.hh:861
static BaryPoint line_barycentric_interpolation(BaryPoint first_coords, BaryPoint second_coords, double first_theta, double second_theta, double theta)
Definition: ref_element.cc:571
static unsigned int permutation_index(unsigned int p[n_nodes_per_side])
Definition: ref_element.cc:552
arma::vec::fixed< dim > LocalPoint
Definition: ref_element.hh:166
static unsigned int line_between_faces(unsigned int f1, unsigned int f2)
static std::pair< unsigned int, unsigned int > zeros_positions(const BaryPoint &barycentric, double tolerance=std::numeric_limits< double >::epsilon()*2)
Definition: ref_element.cc:412
Armor::ArmaVec< double, dim+1 > BaryPoint
Definition: ref_element.hh:173
static unsigned int normal_orientation(unsigned int sid)
Definition: ref_element.cc:334
static unsigned int oposite_node(unsigned int sid)
Definition: ref_element.cc:327
static CentersList centers_of_subelements(unsigned int sub_dim)
Definition: ref_element.cc:484
static LocalPoint bary_to_local(const BaryPoint &bp)
Converts from barycentric to local coordinates.
Definition: ref_element.cc:319
Global macros to enhance readability and debugging, general constants.
static FaceBaryPoint barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face)
Definition: ref_element.cc:397
#define xprintf(...)
Definition: system.hh:93
std::vector< std::vector< unsigned int > > _array_to_vec(const std::vector< IdxVector< n >> array_vec)
Definition: ref_element.cc:29
#define ASSERT_LE_DBG(a, b)
Definition of comparative assert macro (Less or Equal) only for debug mode.
Definition: asserts.hh:308
std::array< unsigned int, Size > IdxVector
Definition: ref_element.hh:147
static double side_measure(unsigned int sid)
Definition: system.hh:65
static BaryPoint local_to_bary(const LocalPoint &lp)
Converts from local to barycentric coordinates.
Definition: ref_element.cc:305
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc...
static BarycentricUnitVec make_bary_unit_vec()
Definition: ref_element.cc:436
static BaryPoint clip(const BaryPoint &barycentric)
Definition: ref_element.cc:450
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:300