Flow123d  DF_patch_fe_darcy_complete-579fe1e
assembly_base.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 assembly_base.hh
15  * @brief
16  */
17 
18 #ifndef ASSEMBLY_BASE_HH_
19 #define ASSEMBLY_BASE_HH_
20 
21 
24 #include "fem/eval_points.hh"
25 #include "fem/element_cache_map.hh"
26 #include "fem/update_flags.hh"
27 
28 
29 
30 /**
31  * Base class define empty methods, these methods can be overwite in descendants.
32  */
33 template <unsigned int dim>
35 {
36 public:
37  /**
38  * Constructor
39  *
40  * @param quad_order Order of Quadrature objects.
41  * @param asm_internals Holds shared data with GenericAssembly
42  */
43  AssemblyBase(unsigned int quad_order, AssemblyInternals *asm_internals)
44  : AssemblyBase<dim>() {
45  asm_internals_ = asm_internals;
46  quad_ = new QGauss(dim, 2*quad_order);
47  quad_low_ = new QGauss(dim-1, 2*quad_order);
48  }
49 
50  /// Destructor
51  virtual ~AssemblyBase() {
52  delete quad_;
53  delete quad_low_;
54  }
55 
56  /**
57  * Assembles the volume integrals on cell.
58  *
59  * Method can be overridden and implemented in descendant
60  */
61  virtual inline void cell_integral(FMT_UNUSED DHCellAccessor cell, FMT_UNUSED unsigned int element_patch_idx) {}
62 
63  /**
64  * Assembles the fluxes on the boundary.
65  *
66  * Method can be overridden and implemented in descendant
67  */
68  virtual inline void boundary_side_integral(FMT_UNUSED DHCellSide cell_side) {}
69 
70  /**
71  * Assembles the fluxes between sides on the edge.
72  *
73  * Method can be overwrite and implement in descendant
74  */
75  virtual inline void edge_integral(FMT_UNUSED RangeConvert<DHEdgeSide, DHCellSide> edge_side_range) {}
76 
77  /**
78  * Assembles the fluxes between elements of different dimensions.
79  *
80  * Method can be overridden and implemented in descendant
81  */
82  virtual inline void dimjoin_intergral(FMT_UNUSED DHCellAccessor cell_lower_dim, FMT_UNUSED DHCellSide neighb_side) {}
83 
84  /**
85  * Method prepares object before assemblation (e.g. balance, ...).
86  *
87  * Method can be overridden and implemented in descendant
88  */
89  virtual void begin() {}
90 
91  /**
92  * Method finishes object after assemblation (e.g. balance, ...).
93  *
94  * Method can be overridden and implemented in descendant
95  */
96  virtual void end() {}
97 
98  /**
99  * Create and return BulkIntegral accessor of given quadrature.
100  *
101  * Method is called from descendants during construction / initialization of assembly object.
102  */
103  std::shared_ptr<BulkIntegralAcc<dim>> create_bulk_integral(Quadrature *quad) {
104  ASSERT_PERMANENT_EQ(quad->dim(), dim);
105  std::tuple<uint, uint> tpl = IntegralTplHash::integral_tuple(dim, quad->size());
106  auto result = integrals_.bulk_.insert({
107  tpl,
108  std::make_shared<BulkIntegralAcc<dim>>(asm_internals_->eval_points_, quad, &asm_internals_->fe_values_, &asm_internals_->element_cache_map_)
109  });
110  integral_data_.bulk_.set_size(integrals_.bulk_.size());
111  return result.first->second;
112  }
113 
114  /**
115  * Create and return EdgeIntegral accessor of given quadrature.
116  *
117  * Method is called from descendants during construction / initialization of assembly object.
118  */
119  std::shared_ptr<EdgeIntegralAcc<dim>> create_edge_integral(Quadrature *quad) {
120  ASSERT_PERMANENT_EQ(quad->dim()+1, dim);
121  std::tuple<uint, uint> tpl = IntegralTplHash::integral_tuple(dim, quad->size());
122  auto result = integrals_.edge_.insert({
123  tpl,
124  std::make_shared<EdgeIntegralAcc<dim>>(asm_internals_->eval_points_, quad, &asm_internals_->fe_values_, &asm_internals_->element_cache_map_)
125  });
126  integral_data_.edge_.set_size(integrals_.edge_.size());
127  return result.first->second;
128  }
129 
130 
131  /**
132  * Create and return CouplingIntegral accessor of given quadrature.
133  *
134  * Method is called from descendants during construction / initialization of assembly object.
135  */
136  std::shared_ptr<CouplingIntegralAcc<dim>> create_coupling_integral(Quadrature *quad) {
137  if (dim == 3) return nullptr;
138 
139  ASSERT_PERMANENT_EQ(quad->dim(), dim);
140  std::tuple<uint, uint> tpl = IntegralTplHash::integral_tuple(dim, quad->size());
141  auto result = integrals_.coupling_.insert({
142  tpl,
143  std::make_shared<CouplingIntegralAcc<dim>>(asm_internals_->eval_points_, quad, &asm_internals_->fe_values_, &asm_internals_->element_cache_map_)
144  });
145  integral_data_.coupling_.set_size(integrals_.coupling_.size());
146  return result.first->second;
147  }
148 
149 
150  /**
151  * Create and return BoundaryIntegral accessor of given quadrature.
152  *
153  * Method is called from descendants during construction / initialization of assembly object.
154  */
155  std::shared_ptr<BoundaryIntegralAcc<dim>> create_boundary_integral(Quadrature *quad) {
156  ASSERT_PERMANENT_EQ(quad->dim()+1, dim);
157  std::tuple<uint, uint> tpl = IntegralTplHash::integral_tuple(dim, quad->size());
158  auto result = integrals_.boundary_.insert({
159  tpl,
160  std::make_shared<BoundaryIntegralAcc<dim>>(asm_internals_->eval_points_, quad, &asm_internals_->fe_values_, &asm_internals_->element_cache_map_)
161  });
162  integral_data_.boundary_.set_size(integrals_.boundary_.size());
163  return result.first->second;
164  }
165 
166 
167  /**
168  * Add data of integrals to appropriate structure and register elements to ElementCacheMap.
169  *
170  * Return true if patch is full to its maximal capacity.
171  * Method is called from GenericAssembly::assembly method.
172  */
174  ASSERT_EQ(cell.dim(), dim);
175 
176  if (cell.is_own()) { // Not ghost
177  if (integrals_.bulk_.size() > 0)
178  ++( asm_internals_->fe_values_.ppv(bulk_domain, cell.dim()) ).n_mesh_items_;
179  this->add_volume_integrals(cell);
180  }
181 
182  for( DHCellSide cell_side : cell.side_range() ) {
183  if (cell.is_own()) // Not ghost
184  if ( (cell_side.side().edge().n_sides() == 1) && (cell_side.side().is_boundary()) ) {
185  this->add_boundary_integrals(cell_side);
186  }
187  if ( (cell_side.n_edge_sides() >= min_edge_sides_) && (cell_side.edge_sides().begin()->element().idx() == cell.elm_idx())) {
188  this->add_edge_integrals(cell_side);
189  }
190  }
191 
193 
199  return true;
200  } else {
205  return false;
206  }
207  }
208 
209  /**
210  * Assembles the cell integrals for the given dimension.
211  *
212  * Method is called from GenericAssembly::assembly method.
213  */
214  virtual inline void assemble_cell_integrals() {
215  for (unsigned int i=0; i<integral_data_.bulk_[0].permanent_size(); ++i) {
217  }
218  // Possibly optimization but not so fast as we would assume (needs change interface of cell_integral)
219  /*for (unsigned int i=0; i<element_cache_map_->n_elements(); ++i) {
220  unsigned int elm_start = element_cache_map_->element_chunk_begin(i);
221  if (element_cache_map_->eval_point_data(elm_start).i_eval_point_ != 0) continue;
222  this->cell_integral(i, element_cache_map_->eval_point_data(elm_start).dh_loc_idx_);
223  }*/
224  }
225 
226  /**
227  * Assembles the boundary side integrals for the given dimension.
228  *
229  * Method is called from GenericAssembly::assembly method.
230  */
232  for (unsigned int i=0; i<integral_data_.boundary_[0].permanent_size(); ++i) {
234  }
235  }
236 
237  /**
238  * Assembles the edge integrals for the given dimension.
239  *
240  * Method is called from GenericAssembly::assembly method.
241  */
242  inline void assemble_edge_integrals() {
243  for (unsigned int i=0; i<integral_data_.edge_[0].permanent_size(); ++i) {
244  this->edge_integral(integral_data_.edge_[0][i].edge_side_range);
245  }
246  }
247 
248  /**
249  * Assembles the neighbours integrals for the given dimension.
250  *
251  * Method is called from GenericAssembly::assembly method.
252  */
254  for (unsigned int i=0; i<integral_data_.coupling_[0].permanent_size(); ++i) {
255  this->dimjoin_intergral(integral_data_.coupling_[0][i].cell, integral_data_.coupling_[0][i].side);
256  }
257  }
258 
259  /// Setter of min_edge_sides_
260  void set_min_edge_sides(unsigned int val) {
261  min_edge_sides_ = val;
262  }
263 
264  /**
265  * Clean all integral data structures
266  *
267  * Method is called from GenericAssembly::assembly method.
268  */
274  }
275 
276  /// Getter of integrals_
277  const DimIntegrals<dim> &integrals() const {
278  return integrals_;
279  }
280 
281  /// Getter of integral_data_
282  const IntegralData &integral_data() const {
283  return integral_data_;
284  }
285 
286 protected:
287  /**
288  * Default constructor.
289  *
290  * Be aware if you use this constructor. Quadrature objects must be initialized manually in descendant.
291  */
293  : quad_(nullptr), quad_low_(nullptr), asm_internals_(nullptr), min_edge_sides_(2) {
294  integral_data_.bulk_.set_size(1); // integral data vectors must not be empty
298  }
299 
300  /**
301  * Add data of volume integrals to appropriate data structure.
302  *
303  * Method is used internally in AssemblyBase
304  */
305  inline void add_volume_integrals(const DHCellAccessor &cell) {
306  uint i_int=0;
307  for (auto integral_it : integrals_.bulk_) {
308  uint subset_idx = integral_it.second->get_subset_idx();
309  integral_data_.bulk_[i_int].emplace_back(cell, subset_idx);
310 
311  unsigned int reg_idx = cell.elm().region_idx().idx();
312  // Different access than in other integrals: We can't use range method CellIntegral::points
313  // because it passes element_patch_idx as argument that is not known during patch construction.
314  for (uint i=uint( asm_internals_->eval_points_->subset_begin(dim, subset_idx) );
315  i<uint( asm_internals_->eval_points_->subset_end(dim, subset_idx) ); ++i) {
317  }
318  ++i_int;
319  }
320  }
321 
322  /**
323  * Add data of edge integrals to appropriate data structure.
324  *
325  * Method is used internally in AssemblyBase
326  */
327  inline void add_edge_integrals(const DHCellSide &cell_side) {
328  auto range = cell_side.edge_sides();
329 
330  auto &ppv = asm_internals_->fe_values_.ppv(side_domain, cell_side.dim());
331  uint i_int=0;
332  for (auto integral_it : integrals_.edge_) {
333  integral_data_.edge_[i_int].emplace_back(range, integral_it.second->get_subset_idx());
334 
335  for( DHCellSide edge_side : range ) {
336  add_side_points(integral_it.second, edge_side, ppv);
337  }
338  ++i_int;
339  }
340  }
341 
342  /**
343  * Add data of boundary integrals to appropriate data structure.
344  *
345  * Method is used internally in AssemblyBase
346  */
347  inline void add_boundary_integrals(const DHCellSide &bdr_side) {
348  auto &ppv = asm_internals_->fe_values_.ppv(side_domain, bdr_side.dim());
349 
350  uint i_int=0;
351  for (auto integral_it : integrals_.boundary_) {
352  auto integral = integral_it.second;
353  integral_data_.boundary_[i_int].emplace_back(integral->get_subset_low_idx(), bdr_side,
354  integral->get_subset_high_idx());
355 
356  unsigned int reg_idx = bdr_side.element().region_idx().idx();
357  ++ppv.n_mesh_items_;
358  for (auto p : integral->points(bdr_side) ) {
359  asm_internals_->element_cache_map_.add_eval_point(reg_idx, bdr_side.elem_idx(), p.eval_point_idx(), bdr_side.cell().local_idx());
360 
361  BulkPoint p_bdr = p.point_bdr(bdr_side.cond().element_accessor()); // equivalent point on boundary element
362  unsigned int bdr_reg = bdr_side.cond().element_accessor().region_idx().idx();
363  // invalid local_idx value, DHCellAccessor of boundary element doesn't exist
364  asm_internals_->element_cache_map_.add_eval_point(bdr_reg, bdr_side.cond().bc_ele_idx(), p_bdr.eval_point_idx(), -1);
365  }
366  ++i_int;
367  }
368  }
369 
370  /**
371  * Add data of coupling integrals to appropriate data structure.
372  *
373  * Method is used internally in AssemblyBase
374  */
375  inline void add_coupling_integrals(const DHCellAccessor &cell) {
376  if (dim==3) return;
377  auto &ppv_low = asm_internals_->fe_values_.ppv(bulk_domain, cell.dim());
378  auto &ppv_high = asm_internals_->fe_values_.ppv(side_domain, cell.dim()+1);
379  uint i_int=0;
380  for (auto coupling_integral_it : integrals_.coupling_) {
381  auto coupling_integral = coupling_integral_it.second;
382  // Adds data of bulk points only if bulk point were not added during processing of bulk integral
383  bool add_bulk_points = !( (integrals_.bulk_.size() > 0) & cell.is_own() );
384  if (add_bulk_points) {
385  // add points of low dim element only one time and only if they have not been added in BulkIntegral
386  for( DHCellSide ngh_side : cell.neighb_sides() ) {
387  unsigned int reg_idx_low = cell.elm().region_idx().idx();
388  ++ppv_low.n_mesh_items_;
389  for (auto p : coupling_integral->points(ngh_side) ) {
390  auto p_low = p.lower_dim(cell); // equivalent point on low dim cell
391  asm_internals_->element_cache_map_.add_eval_point(reg_idx_low, cell.elm_idx(), p_low.eval_point_idx(), cell.local_idx());
392  }
393  break;
394  }
395  }
396  // Adds data of side points of all neighbour objects
397  for( DHCellSide ngh_side : cell.neighb_sides() ) { // cell -> elm lower dim, ngh_side -> elm higher dim
398  integral_data_.coupling_[i_int].emplace_back(cell, coupling_integral->get_subset_low_idx(), ngh_side,
399  coupling_integral->get_subset_high_idx());
400  add_side_points(coupling_integral, ngh_side, ppv_high);
401  }
402  ++i_int;
403  }
404  }
405 
406  /**
407  * Common part of add_edge integrals and add_coupling_integrals methods
408  *
409  * Method is used internally in AssemblyBase
410  */
411  template <template <unsigned int> class IntegralAcc>
412  inline void add_side_points(std::shared_ptr< IntegralAcc<dim> > &integral, DHCellSide cell_side, PatchPointValues<3> &ppv) {
413  ++ppv.n_mesh_items_;
414  unsigned int reg_idx = cell_side.element().region_idx().idx();
415  for (auto p : integral->points(cell_side) ) {
416  asm_internals_->element_cache_map_.add_eval_point(reg_idx, cell_side.elem_idx(), p.eval_point_idx(), cell_side.cell().local_idx());
417  }
418  }
419 
420  /// Print update flags to string format.
421  std::string print_update_flags(UpdateFlags u) const {
422  std::stringstream s;
423  s << u;
424  return s.str();
425  }
426 
427  Quadrature *quad_; ///< Quadrature used in assembling methods.
428  Quadrature *quad_low_; ///< Quadrature used in assembling methods (dim-1).
429  DimIntegrals<dim> integrals_; ///< Set of used integrals.
430  AssemblyInternals *asm_internals_; ///< Holds shared internals data with GeneriAssembly
431 
432  /**
433  * Minimal number of sides on edge.
434  *
435  * Edge integral is created and calculated if number of sides is greater or equal than this value. Default value
436  * is 2 and can be changed
437  */
438  unsigned int min_edge_sides_;
439 
440  IntegralData integral_data_; ///< Holds patch data for computing different types of integrals.
441 };
442 
443 
444 template <unsigned int dim>
445 class AssemblyBasePatch : public AssemblyBase<dim>
446 {
447 public:
448  /**
449  * Constructor.
450  *
451  * @param quad_order Specification of Quadrature size.
452  * @param asm_internals Holds shared data with GenericAssembly
453  */
454  AssemblyBasePatch(unsigned int quad_order, AssemblyInternals *asm_internals)
455  : AssemblyBase<dim>(quad_order, asm_internals) {}
456 
457  /// Return number of DOFs
458  inline unsigned int n_dofs() {
459  return this->asm_internals_->fe_values_.template n_dofs<dim>();
460  }
461 
462  /// Return number of DOFs of higher dim element
463  inline unsigned int n_dofs_high() {
464  return this->asm_internals_->fe_values_.template n_dofs_high<dim>();
465  }
466 
467 };
468 
469 
470 #endif /* ASSEMBLY_BASE_HH_ */
#define ASSERT_PERMANENT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:329
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:333
unsigned int n_dofs_high()
Return number of DOFs of higher dim element.
AssemblyBasePatch(unsigned int quad_order, AssemblyInternals *asm_internals)
unsigned int n_dofs()
Return number of DOFs.
void add_coupling_integrals(const DHCellAccessor &cell)
DimIntegrals< dim > integrals_
Set of used integrals.
IntegralData integral_data_
Holds patch data for computing different types of integrals.
virtual void boundary_side_integral(FMT_UNUSED DHCellSide cell_side)
virtual void end()
virtual ~AssemblyBase()
Destructor.
virtual void cell_integral(FMT_UNUSED DHCellAccessor cell, FMT_UNUSED unsigned int element_patch_idx)
void assemble_neighbour_integrals()
unsigned int min_edge_sides_
void add_volume_integrals(const DHCellAccessor &cell)
Quadrature * quad_
Quadrature used in assembling methods.
std::shared_ptr< CouplingIntegralAcc< dim > > create_coupling_integral(Quadrature *quad)
void add_edge_integrals(const DHCellSide &cell_side)
std::shared_ptr< EdgeIntegralAcc< dim > > create_edge_integral(Quadrature *quad)
AssemblyInternals * asm_internals_
Holds shared internals data with GeneriAssembly.
std::shared_ptr< BoundaryIntegralAcc< dim > > create_boundary_integral(Quadrature *quad)
std::shared_ptr< BulkIntegralAcc< dim > > create_bulk_integral(Quadrature *quad)
void assemble_edge_integrals()
void add_side_points(std::shared_ptr< IntegralAcc< dim > > &integral, DHCellSide cell_side, PatchPointValues< 3 > &ppv)
AssemblyBase(unsigned int quad_order, AssemblyInternals *asm_internals)
virtual void begin()
std::string print_update_flags(UpdateFlags u) const
Print update flags to string format.
Quadrature * quad_low_
Quadrature used in assembling methods (dim-1).
const IntegralData & integral_data() const
Getter of integral_data_.
void clean_integral_data()
virtual void dimjoin_intergral(FMT_UNUSED DHCellAccessor cell_lower_dim, FMT_UNUSED DHCellSide neighb_side)
virtual void edge_integral(FMT_UNUSED RangeConvert< DHEdgeSide, DHCellSide > edge_side_range)
void set_min_edge_sides(unsigned int val)
Setter of min_edge_sides_.
void add_boundary_integrals(const DHCellSide &bdr_side)
void assemble_boundary_side_integrals()
bool add_integrals_of_computing_step(DHCellAccessor cell)
const DimIntegrals< dim > & integrals() const
Getter of integrals_.
virtual void assemble_cell_integrals()
uint bc_ele_idx()
Definition: accessors.hh:374
ElementAccessor< 3 > element_accessor()
Base point accessor class.
unsigned int eval_point_idx() const
Return index in EvalPoints object.
static unsigned int get()
Return number of stored elements.
Cell accessor allow iterate over DOF handler cells.
RangeConvert< DHNeighbSide, DHCellSide > neighb_sides() const
Returns range of neighbour cell of lower dimension corresponding to cell of higher dimension.
bool is_own() const
Return true if accessor represents own element (false for ghost element)
unsigned int dim() const
Return dimension of element appropriate to cell.
Range< DHCellSide > side_range() const
Returns range of cell sides.
unsigned int elm_idx() const
Return serial idx to element of loc_ele_idx_.
ElementAccessor< 3 > elm() const
Return ElementAccessor to element of loc_ele_idx_.
unsigned int local_idx() const
Return local index to element (index of DOF handler).
Side accessor allows to iterate over sides of DOF handler cell.
unsigned int elem_idx() const
Boundary cond() const
const DHCellAccessor & cell() const
Return DHCellAccessor appropriate to the side.
RangeConvert< DHEdgeSide, DHCellSide > edge_sides() const
Returns range of all sides looped over common Edge.
unsigned int dim() const
Return dimension of element appropriate to the side.
ElementAccessor< 3 > element() const
RegionIdx region_idx() const
Definition: accessors.hh:201
unsigned int get_simd_rounded_size()
Returns number of eval. points with addition of max simd duplicates due to regions.
void add_eval_point(unsigned int i_reg, unsigned int i_ele, unsigned int i_eval_point, unsigned int dh_loc_idx)
unsigned int position_in_cache(unsigned mesh_elm_idx, bool bdr=false) const
Return position of element stored in ElementCacheMap.
PatchPointValues< spacedim > & ppv(uint domain, uint dim)
Temporary method.
RevertibleValue n_mesh_items_
Number of elements or sides in patch.
Symmetric Gauss-Legendre quadrature formulae on simplices.
Base class for quadrature rules on simplices in arbitrary dimensions.
Definition: quadrature.hh:48
unsigned int size() const
Returns number of quadrature points.
Definition: quadrature.hh:86
unsigned int dim() const
Definition: quadrature.hh:72
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:81
unsigned int uint
@ bulk_domain
@ side_domain
#define FMT_UNUSED
Definition: posix.h:75
Definitions of particular quadrature rules on simplices.
Holds common data shared between GenericAssemblz and Assembly<dim> classes.
PatchFEValues< 3 > fe_values_
Common FEValues object over all dimensions.
ElementCacheMap element_cache_map_
ElementCacheMap according to EvalPoints.
std::shared_ptr< EvalPoints > eval_points_
EvalPoints object shared by all integrals.
Set of integral of given dimension necessary in assemblation.
Set of integral data of given dimension used in assemblation.
RevertableListVector< CouplingIntegralData > coupling_
Holds data for computing couplings integrals.
RevertableListVector< BulkIntegralData > bulk_
Holds data for computing bulk integrals.
RevertableListVector< BoundaryIntegralData > boundary_
Holds data for computing boundary integrals.
RevertableListVector< EdgeIntegralData > edge_
Holds data for computing edge integrals.
static std::tuple< uint, uint > integral_tuple(uint dim, uint quad_size)
Create tuple from dimennsion and size of Quadrature.
void set_size(uint new_size)
Set size of vec_list_.
void revert_temporary()
Erase temporary part of data.
void make_permanent()
Finalize temporary part of data.
void reset()
Clear the list.
Enum type UpdateFlags indicates which quantities are to be recomputed on each finite element cell.
UpdateFlags
Enum type UpdateFlags indicates which quantities are to be recomputed on each finite element cell.
Definition: update_flags.hh:68