Flow123d  release_3.0.0-910-g56968e3
accessors.hh
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 accessors.hh
15  * @brief
16  */
17 
18 #ifndef ACCESSORS_HH_
19 #define ACCESSORS_HH_
20 
21 #include "mesh/bounding_box.hh"
22 #include "mesh/region.hh"
23 #include "mesh/elements.h"
24 #include "mesh/mesh.h"
25 #include "mesh/nodes.hh"
26 #include "mesh/node_accessor.hh"
27 #include "mesh/sides.h"
28 #include "la/distribution.hh"
29 #include <vector>
30 #include <armadillo>
31 
32 /**
33  * Element accessor templated just by dimension of the embedding space, used by Fields.
34  * This should allow algorithms over elements where dimension of particular element is runtime parameter.
35  *
36  * This class suites as interface of Fields to the mesh elements, in particular this accessor knows directly
37  * the region, and also can be used as an accessor that works on the whole region if used by Fields that do not depend on
38  * particular elements as FieldConstant, FiledFormula, and FieldPython.
39  *
40  * TODO:
41  * - make this kind of accessor subclass of FieldCommonBase or at least move it into src/fields
42  * since it has functionality particular for Fields
43  *
44  * Ideas:
45  * need function to calculate intersection (object) of two ElementAccessors, but this definitely should be templated by
46  * dimension of the ref. element (or rather shape of ref. element), here we can have case dispatch
47  *
48  */
49 template <int spacedim>
50 class ElementAccessor {
51 public:
52  /**
53  * Default invalid accessor.
54  */
56  : mesh_(NULL)
57  {}
58 
59  /**
60  * Regional accessor.
61  */
62  ElementAccessor(const Mesh *mesh, RegionIdx r_idx)
63  : dim_(undefined_dim_), mesh_(mesh), r_idx_(r_idx)
64  {}
65 
66  /**
67  * Element accessor.
68  */
69  ElementAccessor(const Mesh *mesh, unsigned int idx)
70  : mesh_(mesh), boundary_(idx>=mesh->n_elements()), element_idx_(idx), r_idx_(element()->region_idx())
71  {
72  dim_=element()->dim();
73  }
74 
75  inline bool is_regional() const {
76  return dim_ == undefined_dim_;
77  }
78 
79  inline bool is_elemental() const {
80  return ( is_valid() && ! is_regional() );
81  }
82 
83  inline bool is_valid() const {
84  return mesh_ != NULL;
85  }
86 
87  inline unsigned int dim() const
88  { return dim_; }
89 
90  inline const Element * element() const {
91  return &(mesh_->element_vec_[element_idx_]);
92  }
93 
94 
95  inline Region region() const
96  { return Region( r_idx_, mesh_->region_db()); }
97 
98  inline RegionIdx region_idx() const
99  { return r_idx_; }
100 
101  /// We need this method after replacing Region by RegionIdx, and movinf RegionDB instance into particular mesh
102  //inline unsigned int region_id() const {
103  // return region().id();
104  //}
105 
106  inline bool is_boundary() const {
107  return boundary_;
108  }
109 
110  /// Return local idx of element in boundary / bulk part of element vector
111  inline unsigned int idx() const {
112  if (boundary_) return ( element_idx_ - mesh_->bulk_size_ );
113  else return element_idx_;
114  }
115 
116  /// Return global idx of element in full element vector
117  inline unsigned int mesh_idx() const {
118  return element_idx_;
119  }
120 
121  inline unsigned int index() const {
122  return (unsigned int)mesh_->find_elem_id(element_idx_);
123  }
124 
125  inline unsigned int proc() const {
127  }
128 
129  inline void inc() {
130  ASSERT(!is_regional()).error("Do not call inc() for regional accessor!");
131  element_idx_++;
132  r_idx_ = element()->region_idx();
133  dim_=element()->dim();
135  }
136 
137  inline SideIter side(const unsigned int loc_index) {
138  return SideIter( Side(mesh_, element_idx_, loc_index) );
139  }
140 
141  inline const SideIter side(const unsigned int loc_index) const {
142  return SideIter( Side(mesh_, element_idx_, loc_index) );
143  }
144 
145  inline const Node * node(unsigned int ni) const {
146  return &(mesh_->node_vec_[element()->node_idx(ni)]);
147  }
148 
149  inline NodeAccessor<3> node_accessor(unsigned int ni) const {
150  return mesh_->node_accessor( element()->node_idx(ni) );
151  }
152 
153  /**
154  * Return bounding box of the element.
155  * Simpler code, but need to check performance penelty.
156  */
157  inline BoundingBox bounding_box() const {
158  return BoundingBox(this->vertex_list());
159  }
160 
161  /**
162  * Return list of element vertices.
163  */
165  vector<arma::vec3> vertices(element()->n_nodes());
166  for(unsigned int i=0; i<element()->n_nodes(); i++) vertices[i]=node(i)->point();
167  return vertices;
168  }
169 
170  /// Computes the measure of the element.
171  double measure() const;
172 
173  /** Computes the Jacobian of the element.
174  * J = det ( 1 1 1 1 )
175  * x1 x2 x3 x4
176  * y1 y2 y3 y4
177  * z1 z2 z3 z4
178  */
179  inline double tetrahedron_jacobian() const
180  {
181  ASSERT(dim() == 3)(dim()).error("Cannot provide Jacobian for dimension other than 3.");
182  return arma::dot( arma::cross(*( node(1) ) - *( node(0) ),
183  *( node(2) ) - *( node(0) )),
184  *( node(3) ) - *( node(0) )
185  );
186  }
187 
188  /// Computes the barycenter.
189  arma::vec::fixed<spacedim> centre() const;
190 
191  /**
192  * Quality of the element based on the smooth and scale-invariant quality measures proposed in:
193  * J. R. Schewchuk: What is a Good Linear Element?
194  *
195  * We scale the measure so that is gives value 1 for regular elements. Line 1d elements
196  * have always quality 1.
197  */
198  double quality_measure_smooth(SideIter side) const;
199 
201  return (element_idx_ == other.element_idx_);
202  }
203 
204  /**
205  * -> dereference operator
206  *
207  * Allow simplify calling of element() method. Example:
208  @code
209  ElementAccessor<3> elm_ac(mesh, index);
210  arma::vec centre;
211  centre = elm_ac.element()->node_idx(0); // full format of access to element
212  centre = elm_ac->node_idx(0); // short format with dereference operator
213  @endcode
214  */
215  inline const Element * operator ->() const {
216  return &(mesh_->element_vec_[element_idx_]);
217  }
218 
219 
220 private:
221  /**
222  * When dim_ == undefined_dim_ ; the value of element_idx_ is invalid.
223  * Is used for ElementAccessors for whole region
224  */
225  static const unsigned int undefined_dim_ = 100;
226 
227  /// Dimension of reference element.
228  unsigned int dim_;
229 
230  /// Pointer to the mesh owning the element.
231  const Mesh *mesh_;
232  /// True if the element is boundary
233  bool boundary_;
234 
235  /// Index into Mesh::element_vec_ array.
236  unsigned int element_idx_;
237 
238  /// Region index.
240 };
241 
242 
243 
244 
245 /******************************************************************* implementations
246  *
247  *
248  */
249 
250 /**
251  * SET THE "METRICS" FIELD IN STRUCT ELEMENT
252  */
253 template <int spacedim>
255  switch (dim()) {
256  case 0:
257  return 1.0;
258  break;
259  case 1:
260  return arma::norm(*( node(1) ) - *( node(0) ) , 2);
261  break;
262  case 2:
263  return
264  arma::norm(
265  arma::cross(*( node(1) ) - *( node(0) ), *( node(2) ) - *( node(0) )),
266  2
267  ) / 2.0 ;
268  break;
269  case 3:
270  return fabs(
271  arma::dot(
272  arma::cross(*( node(1) ) - *( node(0) ), *( node(2) ) - *( node(0) )),
273  *( node(3) ) - *( node(0) ) )
274  ) / 6.0;
275  break;
276  }
277  return 1.0;
278 }
279 
280 /**
281  * SET THE "CENTRE[]" FIELD IN STRUCT ELEMENT
282  */
283 
284 template <int spacedim>
285 arma::vec::fixed<spacedim> ElementAccessor<spacedim>::centre() const {
286  ASSERT(is_valid()).error("Invalid element accessor.");
287  if (is_regional() ) return arma::vec::fixed<spacedim>();
288 
289  arma::vec::fixed<spacedim> centre;
290  centre.zeros();
291 
292  for (unsigned int li=0; li<element()->n_nodes(); li++) {
293  centre += node( li )->point();
294  }
295  centre /= (double) element()->n_nodes();
296  return centre;
297 }
298 
299 
300 template <int spacedim>
302  if (dim_==3) {
303  double sum_faces=0;
304  double face[4];
305  for(unsigned int i=0; i<4; i++, ++side) sum_faces+=( face[i]=side->measure());
306 
307  double sum_pairs=0;
308  for(unsigned int i=0;i<3;i++)
309  for(unsigned int j=i+1;j<4;j++) {
310  unsigned int i_line = RefElement<3>::line_between_faces(i,j);
311  arma::vec line = *node(RefElement<3>::interact(Interaction<0,1>(i_line))[1]) - *node(RefElement<3>::interact(Interaction<0,1>(i_line))[0]);
312  sum_pairs += face[i]*face[j]*arma::dot(line, line);
313  }
314  double regular = (2.0*sqrt(2.0/3.0)/9.0); // regular tetrahedron
315  return fabs( measure()
316  * pow( sum_faces/sum_pairs, 3.0/4.0))/ regular;
317 
318  }
319  if (dim_==2) {
320  return fabs(
321  measure()/
322  pow(
323  arma::norm(*node(1) - *node(0), 2)
324  *arma::norm(*node(2) - *node(1), 2)
325  *arma::norm(*node(0) - *node(2), 2)
326  , 2.0/3.0)
327  ) / ( sqrt(3.0) / 4.0 ); // regular triangle
328  }
329  return 1.0;
330 }
331 
332 #endif /* ACCESSORS_HH_ */
Definition: sides.h:39
unsigned int get_proc(unsigned int idx) const
get processor of the given index
const Element * element() const
Definition: accessors.hh:90
Bounding box in 3d ambient space.
Definition: bounding_box.hh:54
unsigned int n_nodes() const
Definition: elements.h:129
vector< Element > element_vec_
Definition: mesh.h:508
LongIdx * get_row_4_el() const
Definition: mesh.h:167
NodeAccessor< 3 > node_accessor(unsigned int ni) const
Definition: accessors.hh:149
unsigned int dim_
Dimension of reference element.
Definition: accessors.hh:228
Definition: nodes.hh:31
Nodes of a mesh.
bool is_boundary() const
We need this method after replacing Region by RegionIdx, and movinf RegionDB instance into particular...
Definition: accessors.hh:106
RegionIdx region_idx() const
Definition: elements.h:55
unsigned int mesh_idx() const
Return global idx of element in full element vector.
Definition: accessors.hh:117
NodeAccessor< 3 > node_accessor(unsigned int idx) const
Create and return NodeAccessor to node of given idx.
Definition: mesh.cc:732
vector< arma::vec3 > vertex_list() const
Definition: accessors.hh:164
Definition: mesh.h:76
bool is_valid() const
Definition: accessors.hh:83
const Mesh * mesh_
Pointer to the mesh owning the element.
Definition: accessors.hh:231
static unsigned int line_between_faces(unsigned int f1, unsigned int f2)
SideIter side(const unsigned int loc_index)
Definition: accessors.hh:137
const RegionDB & region_db() const
Definition: mesh.h:143
unsigned int element_idx_
Index into Mesh::element_vec_ array.
Definition: accessors.hh:236
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
unsigned int proc() const
Definition: accessors.hh:125
bool operator==(const ElementAccessor< spacedim > &other)
Definition: accessors.hh:200
const SideIter side(const unsigned int loc_index) const
Definition: accessors.hh:141
arma::vec::fixed< spacedim > centre() const
Computes the barycenter.
Definition: accessors.hh:285
unsigned int dim() const
Definition: elements.h:124
static const unsigned int undefined_dim_
Definition: accessors.hh:225
double quality_measure_smooth(SideIter side) const
Definition: accessors.hh:301
bool is_elemental() const
Definition: accessors.hh:79
int find_elem_id(unsigned int pos) const
Return element id (in GMSH file) of element of given position in element vector.
Definition: mesh.h:361
unsigned int node_idx(unsigned int ni) const
Return index (in Mesh::node_vec) of ni-th node.
Definition: elements.h:75
unsigned int index() const
Definition: accessors.hh:121
BoundingBox bounding_box() const
Definition: accessors.hh:157
vector< Node > node_vec_
Definition: mesh.h:525
double measure() const
Computes the measure of the element.
Definition: accessors.hh:254
bool boundary_
True if the element is boundary.
Definition: accessors.hh:233
Distribution * get_el_ds() const
Definition: mesh.h:164
double measure() const
Calculate metrics of the side.
Definition: sides.cc:30
Region region() const
Definition: accessors.hh:95
const Element * operator->() const
Definition: accessors.hh:215
RegionIdx r_idx_
Region index.
Definition: accessors.hh:239
Support classes for parallel programing.
virtual unsigned int n_elements(bool boundary=false) const
Returns count of boundary or bulk elements.
Definition: mesh.h:346
RegionIdx region_idx() const
Definition: accessors.hh:98
ElementAccessor(const Mesh *mesh, unsigned int idx)
Definition: accessors.hh:69
double tetrahedron_jacobian() const
Definition: accessors.hh:179
ElementAccessor(const Mesh *mesh, RegionIdx r_idx)
Definition: accessors.hh:62
unsigned int dim() const
Definition: accessors.hh:87
arma::vec3 & point()
Definition: nodes.hh:67
unsigned int idx() const
Return local idx of element in boundary / bulk part of element vector.
Definition: accessors.hh:111
unsigned int bulk_size_
Count of bulk elements.
Definition: mesh.h:514
const Node * node(unsigned int ni) const
Definition: accessors.hh:145
bool is_regional() const
Definition: accessors.hh:75