Flow123d  DF_patch_fe_data_tables-3c41206
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 
31 
32 
33 
34 template<std::size_t n>
36  std::vector< std::vector<unsigned int> > vec(array_vec.size());
37  for(unsigned int i=0; i<array_vec.size(); i++)
38  for(unsigned int j=0;j<n; j++)
39  vec[i].push_back(array_vec[i][j]);
40  return vec;
41 }
42 
43 
44 
46  = { {0,1} };
47 
49  = { {0,1},
50  {0,2},
51  {1,2}};
52 
54  = { {0,1}, //0
55  {0,2}, //1
56  {0,3}, //2 <-3 (fixed order)
57  {1,2}, //3 <-2
58  {1,3}, //4
59  {2,3}}; //5
60 
61 
63  = { {0},
64  {0}};
65 
67  = { {1,0},
68  {0,2},
69  {2,1}};
70 
71 
72 
73 
74 
75 // Lexicographic order.
77  = { { 0, 1, 2 },
78  { 0, 1, 3 },
79  { 0, 2, 3 },
80  { 1, 2, 3 }};
81 
82 //// Order clockwise, faces opposite to the lines from node_lines.
83 //// !! dependes on S3 inversion
84 //template<> const std::vector<IdxVector<3>> RefElement<3>::node_sides_
85 // = { { { 2, 1, 0 },
86 // { 3, 0, 1 },
87 // { 3, 2, 0 },
88 // { 3, 1, 2 }},
89 // { { 2, 0, 1 },
90 // { 3, 1, 0 },
91 // { 3, 0, 2 },
92 // { 3, 2, 1 }};
93 
94 
95 
96 // lexicographic order
98  = { {0,1,3},
99  {0,2,4},
100  {1,2,5},
101  {3,4,5}};
102 
103 
105  {(1 << 1)} //node 0
106 };
107 
108 
110  {(1 << 1), //node 0
111  (1 << 0)}, //node 1
112  {0, //the element
113  0}
114 };
115 
116 
118  {(1 << 1) | (1 << 2), //node 0
119  (1 << 0) | (1 << 2), //node 1
120  (1 << 0) | (1 << 1)}, //node 2
121  {(1 << 2), //line 0
122  (1 << 1), //line 1
123  (1 << 0)}, //line 2
124  {0, //the element
125  0,
126  0}
127 };
128 
130  {(1 << 1) | (1 << 2) | (1 << 3), //node 0
131  (1 << 0) | (1 << 2) | (1 << 3), //node 1
132  (1 << 0) | (1 << 1) | (1 << 3), //node 2
133  (1 << 0) | (1 << 1) | (1 << 2), //node 3
134  0,
135  0},
136  {(1 << 2) | (1 << 3), //line 0
137  (1 << 1) | (1 << 3), //line 1
138  (1 << 1) | (1 << 2), //line 2
139  (1 << 0) | (1 << 3), //line 3
140  (1 << 0) | (1 << 2), //line 4
141  (1 << 0) | (1 << 1)}, //line 5
142  {1 << 3, //side 0
143  1 << 2, //side 1
144  1 << 1, //side 2
145  1 << 0, //side 3
146  0,
147  0},
148  {0, //the element
149  0,
150  0,
151  0,
152  0,
153  0}
154 };
155 
156 
157 
158 
159 // 0: nodes of nodes
160 // 1: nodes of lines
161 // 2: nodes of sides
162 // 3: nodes of tetrahedron
164  { {0} }
165 };
166 
168  { {0}, {1} },
169  _array_to_vec(line_nodes_)
170 };
171 
173  { {0}, {1}, {2} },
174  _array_to_vec(line_nodes_),
175  { {0,1,2} }
176 };
177 
179  { {0}, {1}, {2}, {3} },
180  _array_to_vec(line_nodes_),
181  _array_to_vec(side_nodes_),
182  { {0,1,2,3} }
183 };
184 
185 
186 template<unsigned int dim>
188 {
189  ASSERT_EQ(lp.n_rows, dim);
190  BaryPoint bp;
191  bp.rows(1, dim ) = lp;
192  bp( 0 ) = 1.0 - arma::sum(lp);
193  return bp;
194 
195  // new armadillo
196  // return arma::join_col( arma::vec::fixed<1>( { 1.0 - arma::sum( local )} ), local);
197 
198 }
199 
200 template<unsigned int dim>
202 {
203  ASSERT_EQ(bp.n_rows, dim+1);
204  LocalPoint lp = bp.rows(1, dim);
205  return lp;
206 }
207 
208 template<unsigned int dim>
209 inline unsigned int RefElement<dim>::oposite_node(unsigned int sid)
210 {
211  return n_sides - sid - 1;
212 }
213 
214 
215 template<unsigned int dim>
216 unsigned int RefElement<dim>::normal_orientation(unsigned int sid)
217 {
218  ASSERT_LT(sid, n_sides).error("Side number is out of range!");
219 
220  return sid % 2;
221 }
222 
223 
224 template<>
225 vec::fixed<1> RefElement<1>::normal_vector(unsigned int sid)
226 {
227  ASSERT_LT(sid, n_sides).error("Side number is out of range!");
228 
229  return node_coords(sid) - node_coords(1-sid);
230 }
231 
232 template<>
233 vec::fixed<2> RefElement<2>::normal_vector(unsigned int sid)
234 {
235  ASSERT_LT(sid, n_sides).error("Side number is out of range!");
236  vec::fixed<2> barycenter, bar_side, n, t;
237 
238  // tangent vector along line
239  t = node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]);
240  // barycenter coordinates
241  barycenter.fill(1./3);
242  // vector from barycenter to the side
243  bar_side = node_coords(line_nodes_[sid][0]) - barycenter;
244  // normal vector to side (modulo sign)
245  n(0) = -t(1);
246  n(1) = t(0);
247  n /= norm(n,2);
248  // check sign of normal vector
249  if (dot(n,bar_side) < 0) n *= -1;
250 
251  return n;
252 }
253 
254 template<>
255 vec::fixed<3> RefElement<3>::normal_vector(unsigned int sid)
256 {
257  ASSERT_LT(sid, n_sides).error("Side number is out of range!");
258  vec::fixed<3> barycenter, bar_side, n, t1, t2;
259 
260  // tangent vectors of side
261  t1 = node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]);
262  t2 = node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0]);
263  // baryucenter coordinates
264  barycenter.fill(0.25);
265  // vector from barycenter to the side
266  bar_side = node_coords(side_nodes_[sid][0]) - barycenter;
267  // normal vector (modulo sign)
268  n = cross(t1,t2);
269  n /= norm(n,2);
270  // check sign of normal vector
271  if (dot(n,bar_side) < 0) n = -n;
272 
273  return n;
274 }
275 
276 
277 
278 template<unsigned int dim>
279 auto RefElement<dim>::normal_vector_array(Eigen::Array<uint,Eigen::Dynamic,1> loc_side_idx_array) -> Eigen::Vector<RefElement<dim>::ArrayDbl,dim>
280 {
281  Eigen::Vector<ArrayDbl,dim> normal_vec_array;
282  for (uint i=0; i<dim; ++i)
283  normal_vec_array(i).resize( loc_side_idx_array.size() );
284  for (uint sid=0; sid<loc_side_idx_array.size(); ++sid) {
285  arma::vec::fixed<dim> n_vec = RefElement<dim>::normal_vector( loc_side_idx_array(sid) );
286  for (uint i=0; i<dim; ++i)
287  normal_vec_array(i)(sid) = n_vec(i);
288  }
289  return normal_vec_array;
290 }
291 
292 
293 
294 template<>
295 auto RefElement<0>::normal_vector_array(FMT_UNUSED Eigen::Array<uint,Eigen::Dynamic,1> loc_side_idx_array) -> Eigen::Vector<RefElement<0>::ArrayDbl,0>
296 {
297  Eigen::Vector<ArrayDbl,0> normal_vec_array;
298  return normal_vec_array;
299 }
300 
301 
302 
303 template<unsigned int dim>
304 auto RefElement<dim>::barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face) -> FaceBaryPoint
305 {
306  ASSERT_EQ(barycentric.n_rows, dim+1);
307  FaceBaryPoint face_barycentric;
308  for(unsigned int i=0; i < dim; i++) {
309 // unsigned int i_sub_node = (i+1)%dim;
310 // unsigned int i_bary = (dim + side_nodes_[i_face][i_sub_node])%(dim+1);
311  unsigned int i_bary = interact_<0,dim-1>(i_face)[i];
312  face_barycentric[i] = barycentric[ i_bary ];
313  }
314  return face_barycentric;
315 }
316 
317 
318 template<unsigned int dim>
319 std::pair<unsigned int, unsigned int> RefElement<dim>::zeros_positions(const BaryPoint &barycentric,
320  double tolerance)
321 {
322  unsigned int zeros = 0;
323  unsigned int n_zeros = 0;
324  for(unsigned int i=0; i < dim+1; i++){
325  if(std::fabs(barycentric[i]) < tolerance)
326  {
327  zeros = zeros | (1 << i);
328  n_zeros++;
329  }
330  }
331 
332  return std::make_pair(n_zeros, zeros);
333 }
334 
335 
336 template<>
337 auto RefElement<0>::clip(const BaryPoint &barycentric) -> BaryPoint
338 {
339  return barycentric;
340 }
341 
342 template<unsigned int dim>
343 auto RefElement<dim>::make_bary_unit_vec()->BarycentricUnitVec
344 {
345  std::vector<arma::vec::fixed<dim+1> > bary_unit_vec(dim+1, arma::zeros(dim+1));
346  for(unsigned int i=0; i<dim; i++) {
347  bary_unit_vec[i][i] = 1.0;
348  bary_unit_vec[i][dim] = -1.0;
349  bary_unit_vec[dim][i] = -1.0 / dim;
350  }
351  bary_unit_vec[dim][dim] = 1.0;
352  return bary_unit_vec;
353 }
354 
355 
356 template<unsigned int dim>
357 auto RefElement<dim>::clip(const BaryPoint &barycentric) -> BaryPoint
358 {
359  static BarycentricUnitVec bary_unit_vec = make_bary_unit_vec();
360  ASSERT_EQ(barycentric.n_rows, dim+1);
361  for(unsigned int i_bary=0; i_bary < dim +1; i_bary ++) {
362  if (barycentric[i_bary] < 0.0) {
363  // index of barycentric coord that is constant on the face i_side
364  // as we use barycentric coords starting with local coordinates:
365  // TODO: rather work only with local coords and/or with canonical barycentric coords
366  unsigned int i_side = (dim - i_bary);
367  // project to face
368  arma::vec projection_to_face(dim+1);
369  //barycentric.print(cout, "input");
370  //cout << "is: " << i_side << endl;
371  //cout << "ibary: " << i_bary << endl;
372  //bary_unit_vec[i_bary].print(cout, "normal");
373  //barycentric.subvec(0, dim-1).print(cout, "bary sub");
374  projection_to_face = barycentric - barycentric[i_bary]*bary_unit_vec[i_bary];
375  //projection_to_face(dim) = 1.0 - arma::sum(projection_to_face.subvec(0, dim-1));
376  //projection_to_face.print(cout, "projection");
377  auto bary_on_face = barycentric_on_face(projection_to_face, i_side);
378  //bary_on_face.print(cout, "b on f");
379  auto sub_clip = RefElement<dim-1>::clip(bary_on_face);
380  //sub_clip.print(cout, "sub clip");
381  return interpolate<dim-1>(sub_clip, i_side);
382  }
383  }
384  return barycentric;
385 
386 }
387 
388 
389 
390 template<unsigned int dim>
391 auto RefElement<dim>::centers_of_subelements(unsigned int sub_dim)->CentersList
392 {
394  if (list.size() == 0) {
395  list.resize(dim+1);
396  for(unsigned int sdim=0; sdim < dim+1; sdim++) {
397  // Temporary solution until we have unified interface to
398  // the internal indexing.
399  // We use the fact that numbering of subelements goes as numbering of
400  // k combinations over nodes.
401 // std::vector<unsigned int> subel_comb(sdim+2);
402  for(auto &sub_el_nodes : nodes_of_subelements[sdim]) {
403  ASSERT_EQ(sub_el_nodes.size(), sdim+1);
404  LocalPoint center = arma::zeros(dim);
405  for( unsigned int i_node : sub_el_nodes)
406  center+=node_coords( i_node );
407  center/=(sdim+1);
408  list[sdim].push_back(center);
409  }
410  }
411  }
412 
413  ASSERT_LE(sub_dim, dim);
414  return list[sub_dim];
415 }
416 
417 
418 template<>
419 double RefElement<1>::side_measure(unsigned int sid)
420 {
421  ASSERT_LT(sid, n_sides).error("Side number is out of range!");
422 
423  return 1;
424 }
425 
426 
427 template<>
428 double RefElement<2>::side_measure(unsigned int sid)
429 {
430  ASSERT_LT(sid, n_sides).error("Side number is out of range!");
431 
432  return norm(node_coords(line_nodes_[sid][1]) - node_coords(line_nodes_[sid][0]),2);
433 }
434 
435 
436 template<>
437 double RefElement<3>::side_measure(unsigned int sid)
438 {
439  ASSERT_LT(sid, n_sides).error("Side number is out of range!");
440 
441  return 0.5*norm(cross(node_coords(side_nodes_[sid][1]) - node_coords(side_nodes_[sid][0]),
442  node_coords(side_nodes_[sid][2]) - node_coords(side_nodes_[sid][0])),2);
443 }
444 
445 
446 
447 template <>
448 unsigned int RefElement<3>::line_between_faces(unsigned int f1, unsigned int f2) {
449  unsigned int i,j;
450  i=j=0;
451  while (side_lines_[f1][i] != side_lines_[f2][j])
452  if (side_lines_[f1][i] < side_lines_[f2][j]) i++;
453  else j++;
454  return side_lines_[f1][i];
455 }
456 
457 
458 /**
459  * Basic line interpolation
460  */
461 template<unsigned int dim>
463  arma::vec::fixed<dim+1> first_coords,
464  arma::vec::fixed<dim+1> second_coords,
465  double first_theta, double second_theta, double theta){
466 
467  arma::vec::fixed<dim+1> bary_interpolated_coords;
468  bary_interpolated_coords = ((theta - first_theta) * second_coords + (second_theta - theta) * first_coords)
469  /(second_theta - first_theta);
470  return bary_interpolated_coords;
471 }
472 
473 template class RefElement<0>;
474 template class RefElement<1>;
475 template class RefElement<2>;
476 template class RefElement<3>;
477 
478 
#define ASSERT_LT(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:301
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
#define ASSERT_LE(a, b)
Definition of comparative assert macro (Less or Equal) only for debug mode.
Definition: asserts.hh:309
static CentersList centers_of_subelements(unsigned int sub_dim)
Definition: ref_element.cc:391
static LocalPoint bary_to_local(const BaryPoint &bp)
Converts from barycentric to local coordinates.
Definition: ref_element.cc:201
static unsigned int normal_orientation(unsigned int sid)
Definition: ref_element.cc:216
Armor::ArmaVec< double, dim > FaceBaryPoint
Definition: ref_element.hh:352
Armor::ArmaVec< double, dim+1 > BaryPoint
Definition: ref_element.hh:351
static FaceBaryPoint barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face)
Definition: ref_element.cc:304
static Eigen::Vector< ArrayDbl, dim > normal_vector_array(Eigen::Array< uint, Eigen::Dynamic, 1 > loc_side_idx_array)
Definition: ref_element.cc:279
static BaryPoint line_barycentric_interpolation(BaryPoint first_coords, BaryPoint second_coords, double first_theta, double second_theta, double theta)
Definition: ref_element.cc:462
arma::vec::fixed< dim > LocalPoint
Definition: ref_element.hh:344
static BaryPoint local_to_bary(const LocalPoint &lp)
Converts from local to barycentric coordinates.
Definition: ref_element.cc:187
static BarycentricUnitVec make_bary_unit_vec()
Definition: ref_element.cc:343
static std::pair< unsigned int, unsigned int > zeros_positions(const BaryPoint &barycentric, double tolerance=std::numeric_limits< double >::epsilon() *2)
Definition: ref_element.cc:319
static unsigned int line_between_faces(unsigned int f1, unsigned int f2)
static BaryPoint clip(const BaryPoint &barycentric)
Definition: ref_element.cc:357
static double side_measure(unsigned int sid)
static LocalPoint normal_vector(unsigned int sid)
static unsigned int oposite_node(unsigned int sid)
Definition: ref_element.cc:209
static constexpr IdxVector< 3 > S3_node_sides[2][4]
Definition: ref_element.hh:300
static constexpr IdxVector< 3 > S3_node_lines[2][4]
Definition: ref_element.hh:328
static constexpr IdxVector< 2 > S3_line_sides[2][6]
Definition: ref_element.hh:312
Eigen::Array< double, Eigen::Dynamic, 1 > ArrayDbl
Definitions of Eigen structures.
Definition: eigen_tools.hh:31
Global macros to enhance readability and debugging, general constants.
unsigned int uint
ArmaVec< double, N > vec
Definition: armor.hh:933
#define FMT_UNUSED
Definition: posix.h:75
std::vector< std::vector< unsigned int > > _array_to_vec(const std::vector< IdxVector< n >> array_vec)
Definition: ref_element.cc:35
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc.
std::array< unsigned int, Size > IdxVector
Definition: ref_element.hh:278