Flow123d  release_2.2.0-33-g759111d
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<unsigned int n>
29 std::vector< std::vector<unsigned int> > _array_to_vec( const unsigned int array[][n], unsigned int m) {
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<> const unsigned int RefElement<1>::side_permutations[][n_nodes_per_side] = { { 0 } };
38 
39 template<> const unsigned int RefElement<2>::side_permutations[][n_nodes_per_side] = { { 0, 1 }, { 1, 0 } };
40 
41 template<> const unsigned int RefElement<3>::side_permutations[][n_nodes_per_side] = {
42  { 0, 1, 2 },
43  { 0, 2, 1 },
44  { 1, 0, 2 },
45  { 1, 2, 0 },
46  { 2, 0, 1 },
47  { 2, 1, 0 }
48 };
49 
50 
51 template<> const unsigned int RefElement<1>::side_nodes[][1] = {
52  { 0 },
53  { 1 }
54 };
55 
56 template<> const unsigned int RefElement<2>::side_nodes[][2] = {
57  { 0, 1},
58  { 0, 2},
59  { 1, 2}
60 };
61 
62 template<> const unsigned int RefElement<3>::side_nodes[][3] = {
63  {0,1,2},
64  {0,1,3},
65  {0,2,3},
66  {1,2,3}
67 };
68 
69 
70 
71 template<> const unsigned int RefElement<3>::side_lines[][3] = {
72  {0,1,2},
73  {0,3,4},
74  {1,3,5},
75  {2,4,5}
76 };
77 
78 
79 
80 template<> const unsigned int RefElement<3>::line_nodes[][2] = {
81  {0,1},
82  {0,2},
83  {1,2},
84  {0,3},
85  {1,3},
86  {2,3}
87 };
88 
89 
91  _array_to_vec(side_nodes, n_sides),
92  { {0,1} }
93 };
94 
96  { {0}, {1}, {2} },
97  _array_to_vec(side_nodes, n_sides),
98  { {0,1,2} }
99 };
100 
102  { {0}, {1}, {2}, {3} },
103  _array_to_vec(line_nodes, n_lines),
104  _array_to_vec(side_nodes, n_sides),
105  { {0,1,2,3} }
106 };
107 
108 
109 template<unsigned int dim>
110 vec::fixed<dim> RefElement<dim>::node_coords(unsigned int nid)
111 {
112  OLD_ASSERT(nid < n_nodes, "Vertex number is out of range!");
113 
114  vec::fixed<dim> p;
115  p.zeros();
116 
117  if (nid > 0)
118  p(nid-1) = 1;
119 
120  return p;
121 }
122 
123 
124 template<unsigned int dim>
125 vec::fixed<dim+1> RefElement<dim>::node_barycentric_coords(unsigned int nid)
126 {
127  OLD_ASSERT(nid < n_nodes, "Vertex number is out of range!");
128 
129  vec::fixed<dim+1> p;
130  p.zeros();
131 
132  if (nid == 0)
133  p(dim) = 1;
134  else
135  p(nid-1) = 1;
136 
137  return p;
138 }
139 
140 
141 template<>
142 vec::fixed<1> RefElement<1>::normal_vector(unsigned int sid)
143 {
144  OLD_ASSERT(sid < n_sides, "Side number is out of range!");
145 
146  return node_coords(sid) - node_coords(1-sid);
147 }
148 
149 template<>
150 vec::fixed<2> RefElement<2>::normal_vector(unsigned int sid)
151 {
152  OLD_ASSERT(sid < n_sides, "Side number is out of range!");
153  vec::fixed<2> barycenter, bar_side, n, t;
154 
155  // tangent vector along line
156  t = node_coords(side_nodes[sid][1]) - node_coords(side_nodes[sid][0]);
157  // barycenter coordinates
158  barycenter.fill(1./3);
159  // vector from barycenter to the side
160  bar_side = node_coords(side_nodes[sid][0]) - barycenter;
161  // normal vector to side (modulo sign)
162  n(0) = -t(1);
163  n(1) = t(0);
164  n /= norm(n,2);
165  // check sign of normal vector
166  if (dot(n,bar_side) < 0) n *= -1;
167 
168  return n;
169 }
170 
171 template<>
172 vec::fixed<3> RefElement<3>::normal_vector(unsigned int sid)
173 {
174  OLD_ASSERT(sid < n_sides, "Side number is out of range!");
175  vec::fixed<3> barycenter, bar_side, n, t1, t2;
176 
177  // tangent vectors of side
178  t1 = node_coords(side_nodes[sid][1]) - node_coords(side_nodes[sid][0]);
179  t2 = node_coords(side_nodes[sid][2]) - node_coords(side_nodes[sid][0]);
180  // baryucenter coordinates
181  barycenter.fill(0.25);
182  // vector from barycenter to the side
183  bar_side = node_coords(side_nodes[sid][0]) - barycenter;
184  // normal vector (modulo sign)
185  n = cross(t1,t2);
186  n /= norm(n,2);
187  // check sign of normal vector
188  if (dot(n,bar_side) < 0) n = -n;
189 
190  return n;
191 }
192 
193 
194 
195 template<unsigned int dim>
196 auto RefElement<dim>::barycentric_on_face(const BaryPoint &barycentric, unsigned int i_face) -> FaceBaryPoint
197 {
198  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
199  FaceBaryPoint face_barycentric;
200  for(unsigned int i=0; i < dim; i++) {
201  unsigned int i_sub_node = (i+1)%dim;
202  unsigned int i_bary = (dim + side_nodes[i_face][i_sub_node])%(dim+1);
203  face_barycentric[i] = barycentric[ i_bary ];
204  }
205  return face_barycentric;
206 }
207 
208 
209 template<unsigned int dim>
210 auto RefElement<dim>::barycentric_from_face(const FaceBaryPoint &face_barycentric, unsigned int i_face) -> BaryPoint
211 {
212  ASSERT_EQ_DBG(face_barycentric.n_rows, dim);
213  BaryPoint barycentric;
214  barycentric.zeros();
215  for(unsigned int i_sub_coord=0; i_sub_coord<dim; i_sub_coord++) {
216  unsigned int i_sub_node = (i_sub_coord+1)%dim;
217  barycentric+=face_barycentric(i_sub_coord)*node_barycentric_coords( side_nodes[i_face][i_sub_node]);
218  }
219  return barycentric;
220 }
221 
222 template<>
223 auto RefElement<0>::clip(const BaryPoint &barycentric) -> BaryPoint
224 {
225  return barycentric;
226 }
227 
228 template<unsigned int dim>
229 auto RefElement<dim>::make_bary_unit_vec()->BarycentricUnitVec
230 {
231  std::vector<arma::vec::fixed<dim+1> > bary_unit_vec(dim+1, arma::zeros(dim+1));
232  for(unsigned int i=0; i<dim; i++) {
233  bary_unit_vec[i][i] = 1.0;
234  bary_unit_vec[i][dim] = -1.0;
235  bary_unit_vec[dim][i] = -1.0 / dim;
236  }
237  bary_unit_vec[dim][dim] = 1.0;
238  return bary_unit_vec;
239 }
240 
241 
242 template<unsigned int dim>
243 auto RefElement<dim>::clip(const BaryPoint &barycentric) -> BaryPoint
244 {
245  static BarycentricUnitVec bary_unit_vec = make_bary_unit_vec();
246  ASSERT_EQ_DBG(barycentric.n_rows, dim+1);
247  for(unsigned int i_bary=0; i_bary < dim +1; i_bary ++) {
248  if (barycentric[i_bary] < 0.0) {
249  // index of barycentric coord that is constant on the face i_side
250  // as we use barycentric coords starting with local coordinates:
251  // TODO: rather work only with local coords and/or with canonical barycentric coords
252  unsigned int i_side = (2*dim - i_bary)%(dim +1);
253  // project to face
254  arma::vec projection_to_face(dim+1);
255  //barycentric.print(cout, "input");
256  //cout << "is: " << i_side << endl;
257  //cout << "ibary: " << i_bary << endl;
258  //bary_unit_vec[i_bary].print(cout, "normal");
259  //barycentric.subvec(0, dim-1).print(cout, "bary sub");
260  projection_to_face = barycentric - barycentric[i_bary]*bary_unit_vec[i_bary];
261  //projection_to_face(dim) = 1.0 - arma::sum(projection_to_face.subvec(0, dim-1));
262  //projection_to_face.print(cout, "projection");
263  auto bary_on_face = barycentric_on_face(projection_to_face, i_side);
264  //bary_on_face.print(cout, "b on f");
265  auto sub_clip = RefElement<dim-1>::clip(bary_on_face);
266  //sub_clip.print(cout, "sub clip");
267  return barycentric_from_face(sub_clip, i_side);
268  }
269  }
270  return barycentric;
271 
272 }
273 
274 
275 
276 template<unsigned int dim>
277 auto RefElement<dim>::centers_of_subelements(unsigned int sub_dim)->CentersList
278 {
280  if (list.size() == 0) {
281  list.resize(dim+1);
282  for(unsigned int sdim=0; sdim < dim+1; sdim++) {
283  // Temporary solution until we have unified interface to
284  // the internal indexing.
285  // We use the fact that numbering of subelements goes as numbering of
286  // k combinations over nodes.
287  std::vector<unsigned int> subel_comb(sdim+2);
288  for(auto &sub_el_nodes : nodes_of_subelements[sdim]) {
289  ASSERT_EQ_DBG(sub_el_nodes.size(), sdim+1);
290  LocalPoint center = arma::zeros(dim);
291  for( unsigned int i_node : sub_el_nodes)
292  center+=node_coords( i_node );
293  center/=(sdim+1);
294  list[sdim].push_back(center);
295  }
296  }
297  }
298 
299  ASSERT_LE_DBG(sub_dim, dim);
300  return list[sub_dim];
301 }
302 
303 
304 template<>
305 double RefElement<1>::side_measure(unsigned int sid)
306 {
307  OLD_ASSERT(sid < n_sides, "Side number is out of range!");
308 
309  return 1;
310 }
311 
312 
313 template<>
314 double RefElement<2>::side_measure(unsigned int sid)
315 {
316  OLD_ASSERT(sid < n_sides, "Side number is out of range!");
317 
318  return norm(node_coords(side_nodes[sid][1]) - node_coords(side_nodes[sid][0]),2);
319 }
320 
321 
322 template<>
323 double RefElement<3>::side_measure(unsigned int sid)
324 {
325  OLD_ASSERT(sid < n_sides, "Side number is out of range!");
326 
327  return 0.5*norm(cross(node_coords(side_nodes[sid][1]) - node_coords(side_nodes[sid][0]),
328  node_coords(side_nodes[sid][2]) - node_coords(side_nodes[sid][0])),2);
329 }
330 
331 
332 
333 template <>
334 unsigned int RefElement<3>::line_between_faces(unsigned int f1, unsigned int f2) {
335  unsigned int i,j;
336  i=j=0;
337  while (side_lines[f1][i] != side_lines[f2][j])
338  if (side_lines[f1][i] < side_lines[f2][j]) i++;
339  else j++;
340  return side_lines[f1][i];
341 }
342 
343 
344 
345 template<unsigned int dim>
346 unsigned int RefElement<dim>::permutation_index(unsigned int p[n_nodes_per_side])
347 {
348  unsigned int index;
349  for (index = 0; index < n_side_permutations; index++)
350  if (equal(p, p + n_nodes_per_side, side_permutations[index]))
351  return index;
352 
353  xprintf(PrgErr, "Side permutation not found.\n");
354 
355  // The following line is present in order to suppress compilers warning
356  // about missing return value.
357  return 0;
358 }
359 
360 
361 template class RefElement<1>;
362 template class RefElement<2>;
363 template class RefElement<3>;
364 
365 
366 
367 
static LocalPoint normal_vector(unsigned int sid)
std::vector< std::vector< unsigned int > > _array_to_vec(const unsigned int array[][n], unsigned int m)
Definition: ref_element.cc:29
#define ASSERT_EQ_DBG(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:331
static LocalPoint node_coords(unsigned int nid)
Definition: ref_element.cc:110
static unsigned int permutation_index(unsigned int p[n_nodes_per_side])
Definition: ref_element.cc:346
arma::vec::fixed< dim > LocalPoint
Definition: ref_element.hh:116
static BaryPoint barycentric_from_face(const FaceBaryPoint &face_barycentric, unsigned int i_face)
Definition: ref_element.cc:210
static unsigned int line_between_faces(unsigned int f1, unsigned int f2)
static CentersList centers_of_subelements(unsigned int sub_dim)
Definition: ref_element.cc:277
#define OLD_ASSERT(...)
Definition: global_defs.h:131
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:196
#define xprintf(...)
Definition: system.hh:92
#define ASSERT_LE_DBG(a, b)
Definition of comparative assert macro (Less or Equal) only for debug mode.
Definition: asserts.hh:307
static double side_measure(unsigned int sid)
Definition: system.hh:64
arma::vec::fixed< dim > FaceBaryPoint
Definition: ref_element.hh:118
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc...
static BarycentricUnitVec make_bary_unit_vec()
Definition: ref_element.cc:229
static BaryPoint clip(const BaryPoint &barycentric)
Definition: ref_element.cc:243
static BaryPoint node_barycentric_coords(unsigned int nid)
Definition: ref_element.cc:125
arma::vec::fixed< dim+1 > BaryPoint
Definition: ref_element.hh:117