Flow123d  intersections_paper-476-gbe68821
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>
31  for(unsigned int i=0; i<m; i++)
32  for(unsigned int j=0;j<n; j++)
33  vec[i].push_back(array[i][j]);
34  return vec;
35 }
36 
37 // template<unsigned int n>
38 // std::vector< std::vector<unsigned int> > _array_to_vec( const unsigned int array[][n], unsigned int m) {
39 // std::vector< std::vector<unsigned int> > vec(m);
40 // for(unsigned int i=0; i<m; i++)
41 // for(unsigned int j=0;j<n; j++)
42 // vec[i].push_back(array[i][j]);
43 // return vec;
44 // }
45 
46 
47 
49  {0,1}
50 };
51 
53  {0,1},
54  {0,2},
55  {1,2}
56 };
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 
67 
69  {0},
70  {0}
71 };
72 
74  {1,0},
75  {0,2},
76  {2,1}
77 };
78 
79 // Order clockwise looking over the vertex to center; smallest index first
81  {0,1,2},
82  {0,4,3},
83  {1,3,5},
84  {2,5,4},
85 };
86 
87 
88 
89 // Lexicographic order.
91  { 0, 1, 2 },
92  { 0, 1, 3 },
93  { 0, 2, 3 },
94  { 1, 2, 3 }
95 };
96 
97 // Order clockwise, faces opposite to the lines from node_lines.
99  { 2, 1, 0 },
100  { 3, 0, 1 },
101  { 3, 2, 0 },
102  { 3, 1, 2 }
103 };
104 
105 // faces ordered clock wise with respect to edge shifted to center of tetrahedron
107  {0,1},
108  {2,0},
109  {1,2},
110  {0,3},
111  {3,1},
112  {2,3}
113 };
114 
115 
117  {0,1,3},
118  {0,2,4},
119  {1,2,5},
120  {3,4,5}
121 };
122 
123 
124 
125 template<> const unsigned int RefElement<1>::side_permutations[][n_nodes_per_side] = { { 0 } };
126 
127 template<> const unsigned int RefElement<2>::side_permutations[][n_nodes_per_side] = { { 0, 1 }, { 1, 0 } };
128 
129 template<> const unsigned int RefElement<3>::side_permutations[][n_nodes_per_side] = {
130  { 0, 1, 2 },
131  { 0, 2, 1 },
132  { 1, 0, 2 },
133  { 1, 2, 0 },
134  { 2, 0, 1 },
135  { 2, 1, 0 }
136 };
137 
138 
140  {(1 << 0) | (1 << 1), //node 0
141  (1 << 0) | (1 << 2), //node 1
142  (1 << 1) | (1 << 2)}, //node 2
143  {(1 << 0), //line 0
144  (1 << 1), //line 1
145  (1 << 2)} //line 2
146 };
147 
149  {(1 << 1) | (1 << 2) | (1 << 3), //node 0
150  (1 << 0) | (1 << 2) | (1 << 3), //node 1
151  (1 << 0) | (1 << 1) | (1 << 3), //node 2
152  (1 << 0) | (1 << 1) | (1 << 2), //node 3
153  0,
154  0},
155  {(1 << 2) | (1 << 3), //line 0
156  (1 << 1) | (1 << 3), //line 1
157  (1 << 1) | (1 << 2), //line 2
158  (1 << 0) | (1 << 3), //line 3
159  (1 << 0) | (1 << 2), //line 4
160  (1 << 0) | (1 << 1)}, //line 5
161  {1 << 3, //side 0
162  1 << 2, //side 1
163  1 << 1, //side 2
164  1 << 0, //side 3
165  0,
166  0}
167 };
168 
169 // template<> const unsigned int RefElement<1>::side_nodes[][1] = {
170 // { 0 },
171 // { 1 }
172 // };
173 //
174 // template<> const unsigned int RefElement<2>::side_nodes[][2] = {
175 // { 0, 1 },
176 // { 0, 2 },
177 // { 1, 2 }
178 // };
179 //
180 // template<> const unsigned int RefElement<3>::side_nodes[][3] = {
181 // { 0, 1, 2 },
182 // { 0, 1, 3 },
183 // { 0, 2, 3 },
184 // { 1, 2, 3 }
185 // };
186 //
187 //
188 //
189 // template<> const unsigned int RefElement<3>::side_lines[][3] = {
190 // {0,1,2},
191 // {0,3,4},
192 // {1,3,5},
193 // {2,4,5}
194 // };
195 //
196 //
197 // template<> const unsigned int RefElement<1>::line_nodes[][2] = {
198 // {0,1}
199 // };
200 //
201 // template<> const unsigned int RefElement<2>::line_nodes[][2] = {
202 // {0,1},
203 // {0,2},
204 // {1,2}
205 // };
206 //
207 // template<> const unsigned int RefElement<3>::line_nodes[][2] = {
208 // {0,1},
209 // {0,2},
210 // {1,2},
211 // {0,3},
212 // {1,3},
213 // {2,3}
214 // };
215 //
216 //
217 // /**
218 // * Indexes of sides for each line - with right orientation
219 // */
220 //
221 // template<> const unsigned int RefElement<3>::line_sides[][2] = {
222 // {0,1},
223 // {2,0},
224 // {0,3},
225 // {1,2},
226 // {3,1},
227 // {2,3}
228 // };
229 //
230 // /**
231 // * Indexes of sides for each line - for Simplex<2>, with right orientation
232 // */
233 // template<> const unsigned int RefElement<2>::line_sides[][2] = {
234 // {1,0},
235 // {0,2},
236 // {2,1}
237 // };
238 
239 
240 // 0: nodes of nodes
241 // 1: nodes of lines
242 // 2: nodes of sides
243 // 3: nodes of tetrahedron
245  { {0},{1} },
246  _array_to_vec(line_nodes_, n_lines)
247 };
248 
250  { {0}, {1}, {2} },
251  _array_to_vec(line_nodes_, n_lines),
252  { {0,1,2} }
253 };
254 
256  { {0}, {1}, {2}, {3} },
257  _array_to_vec(line_nodes_, n_lines),
258  _array_to_vec(side_nodes_, n_sides),
259  { {0,1,2,3} }
260 };
261 
262 
263 template<unsigned int dim>
265 {
266  ASSERT_EQ_DBG(lp.n_rows, dim);
267  BaryPoint bp;
268  bp.rows(1, dim ) = lp;
269  bp( 0 ) = 1.0 - arma::sum(lp);
270  return bp;
271 
272  // new armadillo
273  // return arma::join_col( arma::vec::fixed<1>( { 1.0 - arma::sum( local )} ), local);
274 
275 }
276 
277 template<unsigned int dim>
279 {
280  ASSERT_EQ_DBG(bp.n_rows, dim+1);
281  LocalPoint lp = bp.rows(1, dim);
282  return lp;
283 }
284 
285 template<unsigned int dim>
286 inline unsigned int RefElement<dim>::oposite_node(unsigned int sid)
287 {
288  return n_sides - sid - 1;
289 }
290 
291 
292 template<unsigned int dim>
293 unsigned int RefElement<dim>::normal_orientation(unsigned int sid)
294 {
295  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
296 
297  return sid % 2;
298 }
299 
300 
301 template<>
302 vec::fixed<1> RefElement<1>::normal_vector(unsigned int sid)
303 {
304  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
305 
306  return node_coords(sid) - node_coords(1-sid);
307 }
308 
309 template<>
310 vec::fixed<2> RefElement<2>::normal_vector(unsigned int sid)
311 {
312  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
313  vec::fixed<2> barycenter, bar_side, n, t;
314 
315  // tangent vector along line
316  t = node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]);
317  // barycenter coordinates
318  barycenter.fill(1./3);
319  // vector from barycenter to the side
320  bar_side = node_coords(line_nodes_[sid][0]) - barycenter;
321  // normal vector to side (modulo sign)
322  n(0) = -t(1);
323  n(1) = t(0);
324  n /= norm(n,2);
325  // check sign of normal vector
326  if (dot(n,bar_side) < 0) n *= -1;
327 
328  return n;
329 }
330 
331 template<>
332 vec::fixed<3> RefElement<3>::normal_vector(unsigned int sid)
333 {
334  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
335  vec::fixed<3> barycenter, bar_side, n, t1, t2;
336 
337  // tangent vectors of side
338  t1 = node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]);
339  t2 = node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0]);
340  // baryucenter coordinates
341  barycenter.fill(0.25);
342  // vector from barycenter to the side
343  bar_side = node_coords(side_nodes_[sid][0]) - barycenter;
344  // normal vector (modulo sign)
345  n = cross(t1,t2);
346  n /= norm(n,2);
347  // check sign of normal vector
348  if (dot(n,bar_side) < 0) n = -n;
349 
350  return n;
351 }
352 
353 
354 
355 template<unsigned int dim>
356 auto RefElement<dim>::barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face) -> FaceBaryPoint
357 {
358  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
359  FaceBaryPoint face_barycentric;
360  for(unsigned int i=0; i < dim; i++) {
361 // unsigned int i_sub_node = (i+1)%dim;
362 // unsigned int i_bary = (dim + side_nodes_[i_face][i_sub_node])%(dim+1);
363  unsigned int i_bary = interact_<0,dim-1>(i_face)[i];
364  face_barycentric[i] = barycentric[ i_bary ];
365  }
366  return face_barycentric;
367 }
368 
369 
370 template<>
371 auto RefElement<0>::clip(const BaryPoint &barycentric) -> BaryPoint
372 {
373  return barycentric;
374 }
375 
376 template<unsigned int dim>
377 auto RefElement<dim>::make_bary_unit_vec()->BarycentricUnitVec
378 {
379  std::vector<arma::vec::fixed<dim+1> > bary_unit_vec(dim+1, arma::zeros(dim+1));
380  for(unsigned int i=0; i<dim; i++) {
381  bary_unit_vec[i][i] = 1.0;
382  bary_unit_vec[i][dim] = -1.0;
383  bary_unit_vec[dim][i] = -1.0 / dim;
384  }
385  bary_unit_vec[dim][dim] = 1.0;
386  return bary_unit_vec;
387 }
388 
389 
390 template<unsigned int dim>
391 auto RefElement<dim>::clip(const BaryPoint &barycentric) -> BaryPoint
392 {
393  static BarycentricUnitVec bary_unit_vec = make_bary_unit_vec();
394  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
395  for(unsigned int i_bary=0; i_bary < dim +1; i_bary ++) {
396  if (barycentric[i_bary] < 0.0) {
397  // index of barycentric coord that is constant on the face i_side
398  // as we use barycentric coords starting with local coordinates:
399  // TODO: rather work only with local coords and/or with canonical barycentric coords
400  unsigned int i_side = (dim - i_bary);
401  // project to face
402  arma::vec projection_to_face(dim+1);
403  //barycentric.print(cout, "input");
404  //cout << "is: " << i_side << endl;
405  //cout << "ibary: " << i_bary << endl;
406  //bary_unit_vec[i_bary].print(cout, "normal");
407  //barycentric.subvec(0, dim-1).print(cout, "bary sub");
408  projection_to_face = barycentric - barycentric[i_bary]*bary_unit_vec[i_bary];
409  //projection_to_face(dim) = 1.0 - arma::sum(projection_to_face.subvec(0, dim-1));
410  //projection_to_face.print(cout, "projection");
411  auto bary_on_face = barycentric_on_face(projection_to_face, i_side);
412  //bary_on_face.print(cout, "b on f");
413  auto sub_clip = RefElement<dim-1>::clip(bary_on_face);
414  //sub_clip.print(cout, "sub clip");
415  return interpolate<dim-1>(sub_clip, i_side);
416  }
417  }
418  return barycentric;
419 
420 }
421 
422 
423 
424 template<unsigned int dim>
425 auto RefElement<dim>::centers_of_subelements(unsigned int sub_dim)->CentersList
426 {
428  if (list.size() == 0) {
429  list.resize(dim+1);
430  for(unsigned int sdim=0; sdim < dim+1; sdim++) {
431  // Temporary solution until we have unified interface to
432  // the internal indexing.
433  // We use the fact that numbering of subelements goes as numbering of
434  // k combinations over nodes.
435 // std::vector<unsigned int> subel_comb(sdim+2);
436  for(auto &sub_el_nodes : nodes_of_subelements[sdim]) {
437  ASSERT_EQ_DBG(sub_el_nodes.size(), sdim+1);
438  LocalPoint center = arma::zeros(dim);
439  for( unsigned int i_node : sub_el_nodes)
440  center+=node_coords( i_node );
441  center/=(sdim+1);
442  list[sdim].push_back(center);
443  }
444  }
445  }
446 
447  ASSERT_LE_DBG(sub_dim, dim);
448  return list[sub_dim];
449 }
450 
451 
452 template<>
453 double RefElement<1>::side_measure(unsigned int sid)
454 {
455  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
456 
457  return 1;
458 }
459 
460 
461 template<>
462 double RefElement<2>::side_measure(unsigned int sid)
463 {
464  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
465 
466  return norm(node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]),2);
467 }
468 
469 
470 template<>
471 double RefElement<3>::side_measure(unsigned int sid)
472 {
473  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
474 
475  return 0.5*norm(cross(node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]),
476  node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0])),2);
477 }
478 
479 
480 
481 template <>
482 unsigned int RefElement<3>::line_between_faces(unsigned int f1, unsigned int f2) {
483  unsigned int i,j;
484  i=j=0;
485  while (side_lines_[f1][i] != side_lines_[f2][j])
486  if (side_lines_[f1][i] < side_lines_[f2][j]) i++;
487  else j++;
488  return side_lines_[f1][i];
489 }
490 
491 
492 template<unsigned int dim>
493 unsigned int RefElement<dim>::permutation_index(unsigned int p[n_nodes_per_side])
494 {
495  unsigned int index;
496  for (index = 0; index < n_side_permutations; index++)
497  if (equal(p, p + n_nodes_per_side, side_permutations[index]))
498  return index;
499 
500  xprintf(PrgErr, "Side permutation not found.\n");
501 
502  // The following line is present in order to suppress compilers warning
503  // about missing return value.
504  return 0;
505 }
506 
507 
508 /**
509  * Basic line interpolation
510  */
511 template<unsigned int dim>
513  arma::vec::fixed<dim+1> first_coords,
514  arma::vec::fixed<dim+1> second_coords,
515  double first_theta, double second_theta, double theta){
516 
517  arma::vec::fixed<dim+1> bary_interpolated_coords;
518  bary_interpolated_coords = ((theta - first_theta) * second_coords + (second_theta - theta) * first_coords)
519  /(second_theta - first_theta);
520  return bary_interpolated_coords;
521 };
522 
523 template class RefElement<1>;
524 template class RefElement<2>;
525 template class RefElement<3>;
526 
527 
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
std::vector< std::vector< unsigned int > > _array_to_vec(const IdxVector< n > array[], unsigned int m)
Definition: ref_element.cc:29
static BaryPoint line_barycentric_interpolation(BaryPoint first_coords, BaryPoint second_coords, double first_theta, double second_theta, double theta)
Definition: ref_element.cc:512
static unsigned int permutation_index(unsigned int p[n_nodes_per_side])
Definition: ref_element.cc:493
arma::vec::fixed< dim > LocalPoint
Definition: ref_element.hh:163
static unsigned int line_between_faces(unsigned int f1, unsigned int f2)
static unsigned int normal_orientation(unsigned int sid)
Definition: ref_element.cc:293
static unsigned int oposite_node(unsigned int sid)
Definition: ref_element.cc:286
static CentersList centers_of_subelements(unsigned int sub_dim)
Definition: ref_element.cc:425
static LocalPoint bary_to_local(const BaryPoint &bp)
Converts from barycentric to local coordinates.
Definition: ref_element.cc:278
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:356
#define xprintf(...)
Definition: system.hh:87
#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:144
static double side_measure(unsigned int sid)
Definition: system.hh:59
arma::vec::fixed< dim > FaceBaryPoint
Definition: ref_element.hh:171
static BaryPoint local_to_bary(const LocalPoint &lp)
Converts from local to barycentric coordinates.
Definition: ref_element.cc:264
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc...
static BarycentricUnitVec make_bary_unit_vec()
Definition: ref_element.cc:377
static BaryPoint clip(const BaryPoint &barycentric)
Definition: ref_element.cc:391
arma::vec::fixed< dim+1 > BaryPoint
Definition: ref_element.hh:170
IntersectionPoint * interpolate(const IntersectionPoint &A1, const IntersectionPoint &A2, double t)
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:300