Flow123d  JS_before_hm-1754-g1847fd3ed
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 
116 
117 
119  {(1 << 1)} //node 0
120 };
121 
122 
124  {(1 << 1), //node 0
125  (1 << 0)}, //node 1
126  {0, //the element
127  0}
128 };
129 
130 
132  {(1 << 1) | (1 << 2), //node 0
133  (1 << 0) | (1 << 2), //node 1
134  (1 << 0) | (1 << 1)}, //node 2
135  {(1 << 2), //line 0
136  (1 << 1), //line 1
137  (1 << 0)}, //line 2
138  {0, //the element
139  0,
140  0}
141 };
142 
144  {(1 << 1) | (1 << 2) | (1 << 3), //node 0
145  (1 << 0) | (1 << 2) | (1 << 3), //node 1
146  (1 << 0) | (1 << 1) | (1 << 3), //node 2
147  (1 << 0) | (1 << 1) | (1 << 2), //node 3
148  0,
149  0},
150  {(1 << 2) | (1 << 3), //line 0
151  (1 << 1) | (1 << 3), //line 1
152  (1 << 1) | (1 << 2), //line 2
153  (1 << 0) | (1 << 3), //line 3
154  (1 << 0) | (1 << 2), //line 4
155  (1 << 0) | (1 << 1)}, //line 5
156  {1 << 3, //side 0
157  1 << 2, //side 1
158  1 << 1, //side 2
159  1 << 0, //side 3
160  0,
161  0},
162  {0, //the element
163  0,
164  0,
165  0,
166  0,
167  0}
168 };
169 
170 
171 
172 
173 // template<> const unsigned int RefElement<1>::side_nodes[][1] = {
174 // { 0 },
175 // { 1 }
176 // };
177 //
178 // template<> const unsigned int RefElement<2>::side_nodes[][2] = {
179 // { 0, 1 },
180 // { 0, 2 },
181 // { 1, 2 }
182 // };
183 //
184 // template<> const unsigned int RefElement<3>::side_nodes[][3] = {
185 // { 0, 1, 2 },
186 // { 0, 1, 3 },
187 // { 0, 2, 3 },
188 // { 1, 2, 3 }
189 // };
190 //
191 //
192 //
193 // template<> const unsigned int RefElement<3>::side_lines[][3] = {
194 // {0,1,2},
195 // {0,3,4},
196 // {1,3,5},
197 // {2,4,5}
198 // };
199 //
200 //
201 // template<> const unsigned int RefElement<1>::line_nodes[][2] = {
202 // {0,1}
203 // };
204 //
205 // template<> const unsigned int RefElement<2>::line_nodes[][2] = {
206 // {0,1},
207 // {0,2},
208 // {1,2}
209 // };
210 //
211 // template<> const unsigned int RefElement<3>::line_nodes[][2] = {
212 // {0,1},
213 // {0,2},
214 // {1,2},
215 // {0,3},
216 // {1,3},
217 // {2,3}
218 // };
219 //
220 //
221 // /**
222 // * Indexes of sides for each line - with right orientation
223 // */
224 //
225 // template<> const unsigned int RefElement<3>::line_sides[][2] = {
226 // {0,1},
227 // {2,0},
228 // {0,3},
229 // {1,2},
230 // {3,1},
231 // {2,3}
232 // };
233 //
234 // /**
235 // * Indexes of sides for each line - for Simplex<2>, with right orientation
236 // */
237 // template<> const unsigned int RefElement<2>::line_sides[][2] = {
238 // {1,0},
239 // {0,2},
240 // {2,1}
241 // };
242 
243 
244 // 0: nodes of nodes
245 // 1: nodes of lines
246 // 2: nodes of sides
247 // 3: nodes of tetrahedron
249  { {0} }
250 };
251 
253  { {0}, {1} },
254  _array_to_vec(line_nodes_)
255 };
256 
258  { {0}, {1}, {2} },
259  _array_to_vec(line_nodes_),
260  { {0,1,2} }
261 };
262 
264  { {0}, {1}, {2}, {3} },
265  _array_to_vec(line_nodes_),
266  _array_to_vec(side_nodes_),
267  { {0,1,2,3} }
268 };
269 
270 
271 template<unsigned int dim>
273 {
274  ASSERT_EQ_DBG(lp.n_rows, dim);
275  BaryPoint bp;
276  bp.rows(1, dim ) = lp;
277  bp( 0 ) = 1.0 - arma::sum(lp);
278  return bp;
279 
280  // new armadillo
281  // return arma::join_col( arma::vec::fixed<1>( { 1.0 - arma::sum( local )} ), local);
282 
283 }
284 
285 template<unsigned int dim>
287 {
288  ASSERT_EQ_DBG(bp.n_rows, dim+1);
289  LocalPoint lp = bp.rows(1, dim);
290  return lp;
291 }
292 
293 template<unsigned int dim>
294 inline unsigned int RefElement<dim>::oposite_node(unsigned int sid)
295 {
296  return n_sides - sid - 1;
297 }
298 
299 
300 template<unsigned int dim>
301 unsigned int RefElement<dim>::normal_orientation(unsigned int sid)
302 {
303  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
304 
305  return sid % 2;
306 }
307 
308 
309 template<>
310 vec::fixed<1> RefElement<1>::normal_vector(unsigned int sid)
311 {
312  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
313 
314  return node_coords(sid) - node_coords(1-sid);
315 }
316 
317 template<>
318 vec::fixed<2> RefElement<2>::normal_vector(unsigned int sid)
319 {
320  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
321  vec::fixed<2> barycenter, bar_side, n, t;
322 
323  // tangent vector along line
324  t = node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]);
325  // barycenter coordinates
326  barycenter.fill(1./3);
327  // vector from barycenter to the side
328  bar_side = node_coords(line_nodes_[sid][0]) - barycenter;
329  // normal vector to side (modulo sign)
330  n(0) = -t(1);
331  n(1) = t(0);
332  n /= norm(n,2);
333  // check sign of normal vector
334  if (dot(n,bar_side) < 0) n *= -1;
335 
336  return n;
337 }
338 
339 template<>
340 vec::fixed<3> RefElement<3>::normal_vector(unsigned int sid)
341 {
342  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
343  vec::fixed<3> barycenter, bar_side, n, t1, t2;
344 
345  // tangent vectors of side
346  t1 = node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]);
347  t2 = node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0]);
348  // baryucenter coordinates
349  barycenter.fill(0.25);
350  // vector from barycenter to the side
351  bar_side = node_coords(side_nodes_[sid][0]) - barycenter;
352  // normal vector (modulo sign)
353  n = cross(t1,t2);
354  n /= norm(n,2);
355  // check sign of normal vector
356  if (dot(n,bar_side) < 0) n = -n;
357 
358  return n;
359 }
360 
361 
362 
363 template<unsigned int dim>
364 auto RefElement<dim>::barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face) -> FaceBaryPoint
365 {
366  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
367  FaceBaryPoint face_barycentric;
368  for(unsigned int i=0; i < dim; i++) {
369 // unsigned int i_sub_node = (i+1)%dim;
370 // unsigned int i_bary = (dim + side_nodes_[i_face][i_sub_node])%(dim+1);
371  unsigned int i_bary = interact_<0,dim-1>(i_face)[i];
372  face_barycentric[i] = barycentric[ i_bary ];
373  }
374  return face_barycentric;
375 }
376 
377 
378 template<unsigned int dim>
379 std::pair<unsigned int, unsigned int> RefElement<dim>::zeros_positions(const BaryPoint &barycentric,
380  double tolerance)
381 {
382  unsigned int zeros = 0;
383  unsigned int n_zeros = 0;
384  for(unsigned int i=0; i < dim+1; i++){
385  if(std::fabs(barycentric[i]) < tolerance)
386  {
387  zeros = zeros | (1 << i);
388  n_zeros++;
389  }
390  }
391 
392  return std::make_pair(n_zeros, zeros);
393 }
394 
395 
396 template<>
397 auto RefElement<0>::clip(const BaryPoint &barycentric) -> BaryPoint
398 {
399  return barycentric;
400 }
401 
402 template<unsigned int dim>
403 auto RefElement<dim>::make_bary_unit_vec()->BarycentricUnitVec
404 {
405  std::vector<arma::vec::fixed<dim+1> > bary_unit_vec(dim+1, arma::zeros(dim+1));
406  for(unsigned int i=0; i<dim; i++) {
407  bary_unit_vec[i][i] = 1.0;
408  bary_unit_vec[i][dim] = -1.0;
409  bary_unit_vec[dim][i] = -1.0 / dim;
410  }
411  bary_unit_vec[dim][dim] = 1.0;
412  return bary_unit_vec;
413 }
414 
415 
416 template<unsigned int dim>
417 auto RefElement<dim>::clip(const BaryPoint &barycentric) -> BaryPoint
418 {
419  static BarycentricUnitVec bary_unit_vec = make_bary_unit_vec();
420  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
421  for(unsigned int i_bary=0; i_bary < dim +1; i_bary ++) {
422  if (barycentric[i_bary] < 0.0) {
423  // index of barycentric coord that is constant on the face i_side
424  // as we use barycentric coords starting with local coordinates:
425  // TODO: rather work only with local coords and/or with canonical barycentric coords
426  unsigned int i_side = (dim - i_bary);
427  // project to face
428  arma::vec projection_to_face(dim+1);
429  //barycentric.print(cout, "input");
430  //cout << "is: " << i_side << endl;
431  //cout << "ibary: " << i_bary << endl;
432  //bary_unit_vec[i_bary].print(cout, "normal");
433  //barycentric.subvec(0, dim-1).print(cout, "bary sub");
434  projection_to_face = barycentric - barycentric[i_bary]*bary_unit_vec[i_bary];
435  //projection_to_face(dim) = 1.0 - arma::sum(projection_to_face.subvec(0, dim-1));
436  //projection_to_face.print(cout, "projection");
437  auto bary_on_face = barycentric_on_face(projection_to_face, i_side);
438  //bary_on_face.print(cout, "b on f");
439  auto sub_clip = RefElement<dim-1>::clip(bary_on_face);
440  //sub_clip.print(cout, "sub clip");
441  return interpolate<dim-1>(sub_clip, i_side);
442  }
443  }
444  return barycentric;
445 
446 }
447 
448 
449 
450 template<unsigned int dim>
451 auto RefElement<dim>::centers_of_subelements(unsigned int sub_dim)->CentersList
452 {
454  if (list.size() == 0) {
455  list.resize(dim+1);
456  for(unsigned int sdim=0; sdim < dim+1; sdim++) {
457  // Temporary solution until we have unified interface to
458  // the internal indexing.
459  // We use the fact that numbering of subelements goes as numbering of
460  // k combinations over nodes.
461 // std::vector<unsigned int> subel_comb(sdim+2);
462  for(auto &sub_el_nodes : nodes_of_subelements[sdim]) {
463  ASSERT_EQ_DBG(sub_el_nodes.size(), sdim+1);
464  LocalPoint center = arma::zeros(dim);
465  for( unsigned int i_node : sub_el_nodes)
466  center+=node_coords( i_node );
467  center/=(sdim+1);
468  list[sdim].push_back(center);
469  }
470  }
471  }
472 
473  ASSERT_LE_DBG(sub_dim, dim);
474  return list[sub_dim];
475 }
476 
477 
478 template<>
479 double RefElement<1>::side_measure(unsigned int sid)
480 {
481  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
482 
483  return 1;
484 }
485 
486 
487 template<>
488 double RefElement<2>::side_measure(unsigned int sid)
489 {
490  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
491 
492  return norm(node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]),2);
493 }
494 
495 
496 template<>
497 double RefElement<3>::side_measure(unsigned int sid)
498 {
499  ASSERT_LT_DBG(sid, n_sides).error("Side number is out of range!");
500 
501  return 0.5*norm(cross(node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]),
502  node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0])),2);
503 }
504 
505 
506 
507 template <>
508 unsigned int RefElement<3>::line_between_faces(unsigned int f1, unsigned int f2) {
509  unsigned int i,j;
510  i=j=0;
511  while (side_lines_[f1][i] != side_lines_[f2][j])
512  if (side_lines_[f1][i] < side_lines_[f2][j]) i++;
513  else j++;
514  return side_lines_[f1][i];
515 }
516 
517 
518 
519 
520 /**
521  * Basic line interpolation
522  */
523 template<unsigned int dim>
525  arma::vec::fixed<dim+1> first_coords,
526  arma::vec::fixed<dim+1> second_coords,
527  double first_theta, double second_theta, double theta){
528 
529  arma::vec::fixed<dim+1> bary_interpolated_coords;
530  bary_interpolated_coords = ((theta - first_theta) * second_coords + (second_theta - theta) * first_coords)
531  /(second_theta - first_theta);
532  return bary_interpolated_coords;
533 }
534 
535 template class RefElement<0>;
536 template class RefElement<1>;
537 template class RefElement<2>;
538 template class RefElement<3>;
539 
540 
RefElement::normal_vector
static LocalPoint normal_vector(unsigned int sid)
ref_element.hh
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc.
RefElement::FaceBaryPoint
Armor::ArmaVec< double, dim > FaceBaryPoint
Definition: ref_element.hh:320
Armor::vec
ArmaVec< double, N > vec
Definition: armor.hh:885
RefElement::line_barycentric_interpolation
static BaryPoint line_barycentric_interpolation(BaryPoint first_coords, BaryPoint second_coords, double first_theta, double second_theta, double theta)
Definition: ref_element.cc:524
RefElement
Definition: ref_element.hh:309
RefElement::normal_orientation
static unsigned int normal_orientation(unsigned int sid)
Definition: ref_element.cc:301
RefElement::BaryPoint
Armor::ArmaVec< double, dim+1 > BaryPoint
Definition: ref_element.hh:319
RefElement::LocalPoint
arma::vec::fixed< dim > LocalPoint
Definition: ref_element.hh:312
std::vector
Definition: doxy_dummy_defs.hh:7
RefElement::zeros_positions
static std::pair< unsigned int, unsigned int > zeros_positions(const BaryPoint &barycentric, double tolerance=std::numeric_limits< double >::epsilon() *2)
Definition: ref_element.cc:379
system.hh
ASSERT_EQ_DBG
#define ASSERT_EQ_DBG(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:332
arma
Definition: doxy_dummy_defs.hh:15
RefElement::make_bary_unit_vec
static BarycentricUnitVec make_bary_unit_vec()
Definition: ref_element.cc:403
RefElement::centers_of_subelements
static CentersList centers_of_subelements(unsigned int sub_dim)
Definition: ref_element.cc:451
RefElement::bary_to_local
static LocalPoint bary_to_local(const BaryPoint &bp)
Converts from barycentric to local coordinates.
Definition: ref_element.cc:286
RefElement::clip
static BaryPoint clip(const BaryPoint &barycentric)
Definition: ref_element.cc:417
_array_to_vec
std::vector< std::vector< unsigned int > > _array_to_vec(const std::vector< IdxVector< n >> array_vec)
Definition: ref_element.cc:29
IdxVector
std::array< unsigned int, Size > IdxVector
Definition: ref_element.hh:293
RefElement::oposite_node
static unsigned int oposite_node(unsigned int sid)
Definition: ref_element.cc:294
tolerance
Definition: isotherm.hh:67
RefElement::barycentric_on_face
static FaceBaryPoint barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face)
Definition: ref_element.cc:364
global_defs.h
Global macros to enhance readability and debugging, general constants.
RefElement::line_between_faces
static unsigned int line_between_faces(unsigned int f1, unsigned int f2)
std
Definition: doxy_dummy_defs.hh:5
ASSERT_LT_DBG
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:300
RefElement::local_to_bary
static BaryPoint local_to_bary(const LocalPoint &lp)
Converts from local to barycentric coordinates.
Definition: ref_element.cc:272
RefElement::side_measure
static double side_measure(unsigned int sid)
ASSERT_LE_DBG
#define ASSERT_LE_DBG(a, b)
Definition of comparative assert macro (Less or Equal) only for debug mode.
Definition: asserts.hh:308
std::list
Definition: doxy_dummy_defs.hh:9