Flow123d  master-469ee9f
element_values.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2019 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 fe_values.cc
15  * @brief Class ElementValues calculates data related to transformation
16  * of reference cell to actual cell (Jacobian, inverse Jacobian,
17  * determinant, point coordinates etc.).
18  * @author Jan Stebel
19  */
20 
21 #include "fem/mapping_p1.hh"
22 #include "quadrature/quadrature.hh"
23 #include "fem/element_values.hh"
24 #include "fem/fem_tools.hh"
25 
26 
27 
28 using namespace arma;
29 using namespace std;
30 
31 
32 
33 
34 
35 
36 
37 
39  : n_points(np)
40 {
41  bar_coords.resize(np);
42  weights.resize(np);
43 }
44 
45 
46 template<unsigned int spacedim>
47 ElementData<spacedim>::ElementData(unsigned int size,
48  UpdateFlags flags,
49  unsigned int dim)
50 : dim_(dim),
51  JxW_values(flags & update_JxW_values ? size : 0),
52  side_JxW_values(flags & update_side_JxW_values ? size : 0),
53  jacobians(spacedim, dim, flags & update_jacobians ? size : 0),
54  determinants(flags & update_volume_elements ? size : 0),
55  inverse_jacobians(dim, spacedim, flags & update_inverse_jacobians ? size : 0),
56  points(spacedim, 1, flags & update_quadrature_points ? size : 0),
57  normal_vectors(spacedim, 1, flags & update_normal_vectors ? size : 0),
58  update_flags(flags)
59 {}
60 
61 
62 template<unsigned int spacedim>
64 {
65  if (cell.is_valid() || side.is_valid())
66  {
67  if (cell.is_valid())
68  printf("cell %d dim %d ", cell.elm_idx(), cell.dim());
69  else if (side.is_valid())
70  printf("cell %d dim %d side %d ", side.elem_idx(), side.dim(), side.side_idx());
71 
72  printf(" det[");
73  for (auto d : determinants) printf("%g ", d); printf("]");
74 
75  printf(" JxW[");
76  for (auto j : JxW_values) printf("%g ", j); printf("]");
77 
78  printf(" side_JxW[");
79  for (auto j : side_JxW_values) printf("%g ", j); printf("]");
80 
81  printf(" nv[");
82  for (unsigned int i=0; i<normal_vectors.size(); i++)
83  {
84  auto n = normal_vectors.vec<spacedim>(i);
85  printf(" [");
86  for (unsigned int c=0; c<spacedim; c++) printf("%g ", n[c]);
87  printf("]");
88  }
89  printf("]\n");
90  }
91 }
92 
93 
94 
95 
96 
97 template<unsigned int spacedim>
99 {
100  ASSERT( q.dim() == dim_ );
101  ASSERT( q.size() == n_points_ );
102  RefElementData *ref_data = new RefElementData(q.size());
103 
104  for (unsigned int i=0; i<q.size(); i++)
105  {
106  switch (q.dim())
107  {
108  case 0:
109  ref_data->bar_coords[i] = arma::vec( "0" );
110  //ref_data->bar_coords[i] = RefElement<0>::local_to_bary(q.point<0>(i));
111  break;
112  case 1:
113  ref_data->bar_coords[i] = RefElement<1>::local_to_bary(q.point<1>(i));
114  break;
115  case 2:
116  ref_data->bar_coords[i] = RefElement<2>::local_to_bary(q.point<2>(i));
117  break;
118  case 3:
119  ref_data->bar_coords[i] = RefElement<3>::local_to_bary(q.point<3>(i));
120  break;
121  default:
122  ASSERT_PERMANENT(false)(q.dim()).error("Unsupported dimension.\n");
123  break;
124  }
125  ref_data->weights[i] = q.weight(i);
126  }
127 
128  return ref_data;
129 }
130 
131 
132 
133 template<unsigned int spacedim>
135 {
136  switch (dim_)
137  {
138  case 0:
139  flags = MappingP1<0,spacedim>::update_each(flags);
140  break;
141  case 1:
142  flags = MappingP1<1,spacedim>::update_each(flags);
143  break;
144  case 2:
145  flags = MappingP1<2,spacedim>::update_each(flags);
146  break;
147  case 3:
148  flags = MappingP1<3,spacedim>::update_each(flags);
149  break;
150  default:
151  ASSERT_PERMANENT(false)(dim_).error("Unsupported dimension.\n");
152  break;
153  }
154  return flags;
155 }
156 
157 
158 
159 template<unsigned int spacedim>
161  Quadrature &_quadrature,
162  UpdateFlags _flags,
163  unsigned int dim)
164 : dim_(dim),
165  n_points_(_quadrature.size()),
166  n_sides_(_quadrature.dim() == dim ? 0 : dim+1),
167  ref_data(nullptr),
168  side_ref_data(n_sides_),
169  data(n_points_, update_each(_flags), dim)
170 {
171  //if (dim == 0) return; // avoid unnecessary allocation of dummy 0 dimensional objects
172  if ( _quadrature.dim() == dim )
173  {
174  // precompute element data
175  ref_data = init_ref_data(_quadrature);
176  }
177  else if ( _quadrature.dim() + 1 == dim )
178  {
179  // precompute side data
180  for (unsigned int sid = 0; sid < n_sides_; sid++)
181  {
182  Quadrature side_quad(dim);
183  // transform the side quadrature points to the cell quadrature points
184  switch (dim)
185  {
186  case 1:
187  side_quad = _quadrature.make_from_side<1>(sid);
188  break;
189  case 2:
190  side_quad = _quadrature.make_from_side<2>(sid);
191  break;
192  case 3:
193  side_quad = _quadrature.make_from_side<3>(sid);
194  break;
195  default:
196  ASSERT_PERMANENT(false)(dim).error("Unsupported dimension.\n");
197  break;
198  }
199  side_ref_data[sid] = init_ref_data(side_quad);
200  }
201  }
202 }
203 
204 
205 template<unsigned int spacedim>
207 {
208  if (ref_data) delete ref_data;
209 
210  for (unsigned int sid=0; sid<n_sides_; sid++)
211  delete side_ref_data[sid];
212 }
213 
214 
215 template<unsigned int spacedim>
217 {
218  ASSERT_EQ( dim_, cell.dim() );
219  data.cell = cell;
220 
221  // calculate Jacobian of mapping, JxW, inverse Jacobian
222  switch (dim_)
223  {
224  case 0:
225  if (cell.is_valid() && data.update_flags & update_quadrature_points)
226  data.points.set(0) = Armor::vec<spacedim>( MappingP1<0, spacedim>::element_map(cell) );
227  break;
228  case 1:
229  fill_data<1>();
230  break;
231  case 2:
232  fill_data<2>();
233  break;
234  case 3:
235  fill_data<3>();
236  break;
237  default:
238  ASSERT_PERMANENT(false)(dim_).error("Unsupported dimension.\n");
239  break;
240  }
241 }
242 
243 
244 template<unsigned int spacedim>
245 void ElementValues<spacedim>::reinit(const Side & cell_side)
246 {
247  ASSERT_EQ( dim_, cell_side.dim()+1 );
248  data.side = cell_side;
249 
250  // calculate Jacobian of mapping, JxW, inverse Jacobian, normal vector(s)
251  switch (dim_)
252  {
253  case 1:
254  fill_data<1>();
255  fill_side_data<1>();
256  break;
257  case 2:
258  fill_data<2>();
259  fill_side_data<2>();
260  break;
261  case 3:
262  fill_data<3>();
263  fill_side_data<3>();
264  break;
265  default:
266  ASSERT_PERMANENT(false)(dim_).error("Unsupported dimension.\n");
267  break;
268  }
269 }
270 
271 
272 template<unsigned int spacedim>
273 template<unsigned int dim>
275 {
276  typename MappingP1<dim,spacedim>::ElementMap coords;
277 
278  if ((data.update_flags & update_jacobians) |
279  (data.update_flags & update_volume_elements) |
280  (data.update_flags & update_JxW_values) |
281  (data.update_flags & update_inverse_jacobians) |
282  (data.update_flags & update_normal_vectors) |
283  (data.update_flags & update_quadrature_points))
284  {
285  if (cell().is_valid())
286  coords = MappingP1<dim,spacedim>::element_map(cell());
287  else
288  coords = MappingP1<dim,spacedim>::element_map(side().element());
289  }
290 
291  // calculation of Jacobian dependent data
292  if ((data.update_flags & update_jacobians) |
293  (data.update_flags & update_volume_elements) |
294  (data.update_flags & update_JxW_values) |
295  (data.update_flags & update_inverse_jacobians) |
296  (data.update_flags & update_normal_vectors))
297  {
298  arma::mat::fixed<spacedim,dim> jac = MappingP1<dim,spacedim>::jacobian(coords);
299 
300  // update Jacobians
301  if (data.update_flags & update_jacobians)
302  for (unsigned int i=0; i<n_points_; i++)
303  data.jacobians.set(i) = Armor::mat<spacedim,dim>( jac );
304 
305  // calculation of determinant dependent data
306  if ((data.update_flags & update_volume_elements) |
307  (data.update_flags & update_JxW_values))
308  {
309  double det = fabs(fe_tools::determinant(jac));
310 
311  // update determinants
312  if (data.update_flags & update_volume_elements)
313  for (unsigned int i=0; i<n_points_; i++)
314  data.determinants[i] = det;
315 
316  // update JxW values
317  if (data.update_flags & update_JxW_values)
318  for (unsigned int i=0; i<n_points_; i++)
319  data.JxW_values[i] = det*ref_data->weights[i];
320  }
321 
322  // update inverse Jacobians
323  if (data.update_flags & update_inverse_jacobians)
324  {
325  arma::mat::fixed<dim,spacedim> ijac;
326  ijac = fe_tools::inverse(jac);
327 // if (dim==spacedim)
328 // {
329 // ijac = inv(jac);
330 // }
331 // else
332 // {
333 // ijac = pinv(jac);
334 // }
335  for (unsigned int i=0; i<n_points_; i++)
336  data.inverse_jacobians.set(i) = Armor::mat<dim,spacedim>( ijac );
337  }
338  }
339 
340  // quadrature points in the actual cell coordinate system
341  if (cell().is_valid() && data.update_flags & update_quadrature_points)
342  {
343  for (unsigned int i=0; i<n_points_; i++)
344  data.points.set(i) = Armor::vec<spacedim>( coords*ref_data->bar_coords[i] );
345  }
346 }
347 
348 
349 template<unsigned int spacedim>
350 template<unsigned int dim>
352 {
353  const unsigned int side_idx = side().side_idx();
354 
355  // calculation of normal vectors to the side
356  if (data.update_flags & update_normal_vectors)
357  {
358  arma::vec::fixed<spacedim> n_cell;
359  n_cell = trans(data.inverse_jacobians.template mat<dim,spacedim>(0))*RefElement<dim>::normal_vector(side_idx);
360  n_cell = n_cell/norm(n_cell,2);
361  for (unsigned int i=0; i<n_points_; i++)
362  data.normal_vectors.set(i) = Armor::vec<spacedim>( n_cell );
363  }
364 
365  // Quadrature points in the actual cell coordinate system.
366  // The points location can vary from side to side.
367  if (data.update_flags & update_quadrature_points)
368  {
370  for (unsigned int i=0; i<n_points_; i++)
371  data.points.set(i) = Armor::vec<spacedim>( coords*side_ref_data[side_idx]->bar_coords[i] );
372  }
373 
374  if (data.update_flags & update_side_JxW_values)
375  {
376  double side_det;
377  if (dim <= 1)
378  {
379  side_det = 1;
380  }
381  else
382  {
383  arma::mat::fixed<spacedim,dim> side_coords;
384  arma::mat::fixed<spacedim, MatrixSizes<dim>::dim_minus_one > side_jac; // some compilers complain for case dim==0
385 
386  // calculation of side Jacobian
387  for (unsigned int n=0; n<dim; n++)
388  for (unsigned int c=0; c<spacedim; c++)
389  side_coords(c,n) = (*data.side.node(n))[c];
390  side_jac = MappingP1<MatrixSizes<dim>::dim_minus_one,spacedim>::jacobian(side_coords);
391 
392  // calculation of JxW
393  side_det = fabs(fe_tools::determinant(side_jac));
394  }
395  for (unsigned int i=0; i<n_points_; i++)
396  data.side_JxW_values[i] = side_det*side_ref_data[side_idx]->weights[i];
397  }
398 }
399 
400 
401 
402 
403 
404 template class ElementValues<3>;
405 
#define ASSERT(expr)
Definition: asserts.hh:351
#define ASSERT_PERMANENT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:348
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
ArmaVec< Type, nr > vec(uint mat_index) const
Definition: armor.hh:869
unsigned int size() const
Definition: armor.hh:776
bool is_valid() const
Definition: accessors.hh:184
unsigned int dim() const
Definition: accessors.hh:188
std::vector< double > determinants
Determinants of Jacobians at quadrature points.
ElementAccessor< spacedim > cell
Iterator to last updated cell.
ElementData(unsigned int size, UpdateFlags flags, unsigned int dim)
Resize the data arrays.
void print()
Print calculated data.
std::vector< double > JxW_values
Transformed quadrature weights.
Armor::array normal_vectors
Normal vectors (spacedim) to the element at the quadrature points lying on a side.
std::vector< double > side_JxW_values
JxW values for sides.
Side side
Iterator to last updated cell side.
Class for computation of data on cell and side.
const unsigned int n_sides_
Number of sides in reference cell.
RefElementData * ref_data
Data on reference element.
ElementValues(Quadrature &_quadrature, UpdateFlags _flags, unsigned int dim)
Constructor.
RefElementData * init_ref_data(const Quadrature &q)
Precompute data on reference element.
void fill_side_data()
Calculates the mapping data on a side of a cell.
~ElementValues()
Correct deallocation of objects created by 'initialize' methods.
std::vector< RefElementData * > side_ref_data
Data on reference element (for each side ).
void reinit(const ElementAccessor< spacedim > &cell)
Update cell-dependent data (gradients, Jacobians etc.)
UpdateFlags update_each(UpdateFlags flags)
Determine quantities to be recomputed on each cell.
void fill_data()
Compute data from reference cell and using MappingP1.
Affine mapping between reference and actual cell.
Definition: mapping_p1.hh:59
static arma::mat::fixed< spacedim, dim > jacobian(const ElementMap &coords)
Definition: mapping_p1.cc:58
arma::mat::fixed< spacedim, dim+1 > ElementMap
Definition: mapping_p1.hh:64
static ElementMap element_map(ElementAccessor< 3 > elm)
Definition: mapping_p1.cc:48
static UpdateFlags update_each(UpdateFlags flags)
Determines which additional quantities have to be computed.
Definition: mapping_p1.cc:30
Base class for quadrature rules on simplices in arbitrary dimensions.
Definition: quadrature.hh:48
Quadrature make_from_side(unsigned int sid) const
Definition: quadrature.cc:47
unsigned int size() const
Returns number of quadrature points.
Definition: quadrature.hh:86
unsigned int dim() const
Definition: quadrature.hh:72
Armor::ArmaVec< double, point_dim > point(unsigned int i) const
Returns the ith quadrature point.
Definition: quadrature.hh:151
double weight(unsigned int i) const
Returns the ith weight.
Definition: quadrature.hh:103
Structure for storing the precomputed element data.
RefElementData(unsigned int np)
Resize vectors to size np.
std::vector< arma::vec > bar_coords
Barycentric coordinates of quadrature points.
std::vector< double > weights
Quadrature weights.
static BaryPoint local_to_bary(const LocalPoint &lp)
Converts from local to barycentric coordinates.
Definition: ref_element.cc:187
static LocalPoint normal_vector(unsigned int sid)
unsigned int elem_idx() const
Returns index of element in Mesh::element_vec_.
Definition: accessors.hh:448
unsigned int side_idx() const
Returns local index of the side on the element.
Definition: accessors.hh:444
bool is_valid() const
Returns true if the side has assigned element.
Definition: accessors.hh:452
unsigned int dim() const
Returns dimension of the side, that is dimension of the element minus one.
Class ElementValues calculates data related to transformation of reference cell to actual cell (Jacob...
Class MappingP1 implements the affine transformation of the unit cell onto the actual cell.
ArmaMat< double, N, M > mat
Definition: armor.hh:936
ArmaVec< double, N > vec
Definition: armor.hh:933
arma::mat::fixed< n, m > inverse(const arma::mat::fixed< m, n > &A)
Calculates inverse of rectangular matrix or pseudoinverse of non-rectangular matrix.
Definition: fem_tools.hh:267
double determinant(const T &M)
Calculates determinant of a rectangular matrix.
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: printf.h:444
Basic definitions of numerical quadrature rules.
UpdateFlags
Enum type UpdateFlags indicates which quantities are to be recomputed on each finite element cell.
Definition: update_flags.hh:68
@ update_volume_elements
Determinant of the Jacobian.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_jacobians
Volume element.
@ update_side_JxW_values
Transformed quadrature weight for cell sides.
@ update_inverse_jacobians
Volume element.
@ update_quadrature_points
Transformed quadrature points.