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