Flow123d  release_2.2.0-914-gf1a3a4f
fe_system.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 fe_system.cc
15  * @brief Class FESystem for compound finite elements.
16  * @author Jan Stebel
17  */
18 
19 #include "fem/fe_system.hh"
20 #include "system/global_defs.h"
21 #include "quadrature/quadrature.hh"
22 
23 using namespace std;
24 
25 
26 
27 template<unsigned int dim, unsigned int spacedim>
29 {
30  OLD_ASSERT(fe->is_primitive(), "FE vector or tensor can olny by created from primitive FE.");
32  t == FEType::FEVectorPiola ||
33  t == FEType::FETensor, "This constructor can be used only for vectors or tensors.");
34 
36 
39  else
41 
42  initialize();
43 }
44 
45 
46 template<unsigned int dim, unsigned int spacedim>
47 FESystem<dim,spacedim>::FESystem(const std::shared_ptr<FiniteElement<dim,spacedim> > &fe, unsigned int n)
48 {
51  initialize();
52 }
53 
54 
55 template<unsigned int dim, unsigned int spacedim>
57 {
59  for (std::shared_ptr<FiniteElement<dim,spacedim> > fe_object : fe)
60  fe_.push_back(fe_object);
61  initialize();
62 }
63 
64 
65 
66 template<unsigned int dim, unsigned int spacedim>
68 {
69  unsigned int fe_index = 0;
70  unsigned int comp_offset = 0;
71  n_components_ = 0;
72  // for each base FE add components, support points, and other
73  // information to the system
74  for (auto fe : fe_)
75  {
76  n_components_ += fe->n_components();
77 
78  switch (fe->type_)
79  {
80  case FEType::FEScalar:
81  scalar_components_.push_back(comp_offset);
82  break;
85  vector_components_.push_back(comp_offset);
86  break;
87  default:
88  OLD_ASSERT(false, "Not implemented.");
89  break;
90  }
91 
92  for (int i=0; i<fe->n_dofs(); ++i)
93  fe_dof_indices_.push_back(DofComponentData(fe_index, i, comp_offset));
94 
95  fe_index++;
96  comp_offset += fe->n_components();
97  }
98 
99  double dof_index = 0;
100  comp_offset = 0;
101  for (auto fe : fe_)
102  {
103  for (unsigned int i=0; i<fe->n_dofs(); i++)
104  {
105  arma::vec coefs(n_components_);
106  coefs.subvec(comp_offset, comp_offset+fe->dof(i).coefs.size()-1) = fe->dof(i).coefs;
107  this->dofs_.push_back(Dof(fe->dof(i).dim, fe->dof(i).n_face_idx, fe->dof(i).coords, coefs, fe->dof(i).type));
108  dof_index++;
109  }
110  comp_offset += fe->n_components();
111  }
112 
113 // if (this->is_primitive_)
114 // {
115 // double dof_index = 0;
116 // // add index of nonzero component for each dof in FESystem
117 // for (auto fe : fe_)
118 // {
119 // for (int i=0; i<fe->n_dofs(); ++i)
120 // this->component_indices_.push_back(fe_dof_indices_[dof_index++].fe_index);
121 // }
122 // } else {
123  dof_index = 0;
124  comp_offset = 0;
125  // add footprint of nonzero components for each dof in FESystem
126  for (auto fe : fe_)
127  {
128  for (int i=0; i<fe->n_dofs(); ++i)
129  {
130  std::vector<bool> nonzeros(n_components_, false);
131  for (unsigned int c=0; c<fe->n_components(); c++)\
132  nonzeros[comp_offset+c] = fe->get_nonzero_components(fe_dof_indices_[dof_index].basis_index)[c];
133  this->nonzero_components_.push_back(nonzeros);
134  dof_index++;
135  }
136  comp_offset += fe->n_components();
137  }
138 // }
139 
140  compute_node_matrix();
141 }
142 
143 
144 
145 template<unsigned int dim, unsigned int spacedim>
146 double FESystem<dim,spacedim>::basis_value(const unsigned int i,
147  const arma::vec::fixed<dim> &p,
148  const unsigned int comp) const
149 {
150  OLD_ASSERT(i <= this->dofs_.size(), "Index of basis function is out of range.");
151 
152  // component index in the base FE
153  int l_comp = comp-fe_dof_indices_[i].component_offset;
154  OLD_ASSERT(l_comp >= 0 && l_comp < fe_[fe_dof_indices_[i].fe_index]->n_components(),
155  "Index of component is out of range.");
156 
157  return fe_[fe_dof_indices_[i].fe_index]->basis_value(fe_dof_indices_[i].basis_index, p, l_comp);
158 }
159 
160 template<unsigned int dim, unsigned int spacedim>
161 arma::vec::fixed<dim> FESystem<dim,spacedim>::basis_grad(const unsigned int i,
162  const arma::vec::fixed<dim> &p,
163  const unsigned int comp) const
164 {
165  OLD_ASSERT(i <= this->dofs_.size(), "Index of basis function is out of range.");
166 
167  // component index in the base FE
168  int l_comp = comp-fe_dof_indices_[i].component_offset;
169  OLD_ASSERT(l_comp >= 0 && l_comp < fe_[fe_dof_indices_[i].fe_index]->n_components(),
170  "Index of component is out of range.");
171 
172  return fe_[fe_dof_indices_[i].fe_index]->basis_grad(fe_dof_indices_[i].basis_index, p, l_comp);
173 }
174 
175 
176 template<unsigned int dim, unsigned int spacedim> inline
178 {
179  UpdateFlags f = flags;
180 
181  for (auto fe : fe_)
182  f |= fe->update_each(flags);
183 
184  return f;
185 }
186 
187 
188 template<unsigned int dim, unsigned int spacedim>
190 {
191  // form the node_matrix of the FESystem as block diagonal matrix
192  // composed of node_matrices of each base FE class
193 
194  this->node_matrix.resize(this->dofs_.size(), this->dofs_.size());
195 
196  unsigned int offset = 0;
197  for (unsigned int i = 0; i < fe_.size(); i++)
198  {
199  this->node_matrix.submat(offset, offset, offset+fe_[i]->n_dofs()-1, offset+fe_[i]->n_dofs()-1)
200  = fe_[i]->node_matrix;
201 
202  offset += fe_[i]->n_dofs();
203  }
204 }
205 
206 
207 template<unsigned int dim, unsigned int spacedim>
209 {
210  FEInternalData *data = new FEInternalData;
212 
213  // first initialize the base FE
214  for (auto fe : fe_)
215  fe_data.push_back(fe->initialize(q));
216 
217  // fill values of basis functions
218  data->ref_shape_values.resize(q.size(), std::vector<arma::vec>(this->dofs_.size(), arma::vec(n_components_)));
219 
220  unsigned int comp_offset = 0;
221  unsigned int dof_offset = 0;
222  for (unsigned int f=0; f<fe_.size(); f++)
223  {
224  // copy the values to subvector
225  for (unsigned int i=0; i<q.size(); i++)
226  for (unsigned int n=0; n<fe_[f]->n_dofs(); n++)
227  data->ref_shape_values[i][dof_offset+n].subvec(comp_offset,comp_offset+fe_[f]->n_components()-1) = fe_data[f]->ref_shape_values[i][n];
228  comp_offset += fe_[f]->n_components();
229  dof_offset += fe_[f]->n_dofs();
230  }
231 
232  // fill gradients of basis functions
233  data->ref_shape_grads.resize(q.size(), std::vector<arma::mat>(this->dofs_.size(), arma::mat(dim,n_components_)));
234 
235  comp_offset = 0;
236  dof_offset = 0;
237  for (unsigned int f=0; f<fe_.size(); f++)
238  {
239  for (unsigned int i=0; i<q.size(); i++)
240  for (unsigned int n=0; n<fe_[f]->n_dofs(); n++)
241  data->ref_shape_grads[i][dof_offset+n].submat(0,comp_offset,dim-1,comp_offset+fe_[f]->n_components()-1) = fe_data[f]->ref_shape_grads[i][n];
242  comp_offset += fe_[f]->n_components();
243  dof_offset += fe_[f]->n_dofs();
244  }
245 
246  for (auto d : fe_data) delete d;
247 
248  return data;
249 }
250 
251 
252 template<unsigned int dim, unsigned int spacedim> inline
254  const Quadrature<dim> &q,
255  FEInternalData &data,
257 {
258  // This method essentially calls fill_fe_values for the FE classes of components
259  // of the FESystem and copies the values to the appropriate structures for FESystem.
260  if (!(fv_data.update_flags & update_values) && !(fv_data.update_flags & update_gradients)) return;
261 
262  std::vector<std::vector<double> > shape_values(q.size(), std::vector<double>(fv_data.shape_values[0].size(), 0.));
264  for (unsigned int k=0; k<q.size(); k++)
265  for (unsigned int i=0; i<fv_data.shape_values[0].size(); i++)
266  shape_gradients[k][i].zeros();
267 
268  unsigned int comp_offset = 0;
269  unsigned int dof_offset = 0;
270  unsigned int shape_offset = 0;
271  for (unsigned int f=0; f<fe_.size(); f++)
272  {
273  // create new FEInternalData object for the base FE
274  // and fill its values/gradients
275  FEInternalData d;
276  FEValuesData<dim,spacedim> sub_fv_data;
277 
278  if (fv_data.update_flags & update_values)
279  {
280  d.ref_shape_values.resize(q.size(), std::vector<arma::vec>(fe_[f]->n_dofs(), arma::vec(fe_[f]->n_components())));
281  for (unsigned int i=0; i<q.size(); i++)
282  for (unsigned int n=0; n<fe_[f]->n_dofs(); n++)
283  d.ref_shape_values[i][n] = data.ref_shape_values[i][dof_offset+n].subvec(comp_offset,comp_offset+fe_[f]->n_components()-1);
284  }
285 
286  if (fv_data.update_flags & update_gradients)
287  {
288  d.ref_shape_grads.resize(q.size(), std::vector<arma::mat>(fe_[f]->n_dofs(), arma::mat(dim,fe_[f]->n_components())));
289  for (unsigned int i=0; i<q.size(); i++)
290  for (unsigned int n=0; n<fe_[f]->n_dofs(); n++)
291  d.ref_shape_grads[i][n] = data.ref_shape_grads[i][dof_offset+n].submat(0,comp_offset,dim-1,comp_offset+fe_[f]->n_components()-1);
292  }
293 
294  // fill fe_values for base FE
295  sub_fv_data.allocate(q.size(), fv_data.update_flags, fe_[f]->n_dofs()*fe_[f]->n_components());
296  sub_fv_data.jacobians = fv_data.jacobians;
297  sub_fv_data.inverse_jacobians = fv_data.inverse_jacobians;
298  sub_fv_data.determinants = fv_data.determinants;
299  fe_[f]->fill_fe_values(q, d, sub_fv_data);
300 
301  // gather fe_values in vectors for FESystem
302  if (fv_data.update_flags & update_values)
303  {
304  for (unsigned int i=0; i<q.size(); i++)
305  for (unsigned int n=0; n<fe_[f]->n_dofs(); n++)
306  for (unsigned int c=0; c<fe_[f]->n_components(); c++)
307  fv_data.shape_values[i][shape_offset+n_components_*n+comp_offset+c] = sub_fv_data.shape_values[i][n*fe_[f]->n_components()+c];
308  }
309 
310  if (fv_data.update_flags & update_gradients)
311  {
312  for (unsigned int i=0; i<q.size(); i++)
313  for (unsigned int n=0; n<fe_[f]->n_dofs(); n++)
314  for (unsigned int c=0; c<fe_[f]->n_components(); c++)
315  fv_data.shape_gradients[i][shape_offset+n_components_*n+comp_offset+c] = sub_fv_data.shape_gradients[i][n*fe_[f]->n_components()+c];
316  }
317 
318  dof_offset += fe_[f]->n_dofs();
319  comp_offset += fe_[f]->n_components();
320  shape_offset += fe_[f]->n_dofs()*n_components_;
321  }
322 }
323 
324 
325 
326 
327 
328 
329 
330 template class FESystem<1,3>;
331 template class FESystem<2,3>;
332 template class FESystem<3,3>;
333 
334 
335 
Shape function values.
Definition: update_flags.hh:87
UpdateFlags
Enum type UpdateFlags indicates which quantities are to be recomputed on each finite element cell...
Definition: update_flags.hh:67
void init(bool primitive=true, FEType type=FEScalar)
Clears all internal structures.
void compute_node_matrix() override
Initializes the node_matrix for computing the coefficients of the shape functions in the raw basis of...
Definition: fe_system.cc:189
void fill_fe_values(const Quadrature< dim > &q, FEInternalData &data, FEValuesData< dim, spacedim > &fv_data) override
Computes the shape function values and gradients on the actual cell and fills the FEValues structure...
Definition: fe_system.cc:253
std::vector< arma::mat::fixed< dim, spacedim > > inverse_jacobians
Inverse Jacobians at the quadrature points.
Definition: fe_values.hh:84
UpdateFlags update_flags
Flags that indicate which finite element quantities are to be computed.
Definition: fe_values.hh:123
Class FESystem for compound finite elements.
FEType
void initialize()
Initialization of the internal structures from the vector of base FE.
Definition: fe_system.cc:67
void allocate(unsigned int size, UpdateFlags flags, unsigned n_comp)
Resize the data arrays.
Definition: fe_values.cc:42
Base class for quadrature rules on simplices in arbitrary dimensions.
Definition: fe_values.hh:32
UpdateFlags update_each(UpdateFlags flags) override
Decides which additional quantities have to be computed for each cell.
Definition: fe_system.cc:177
#define OLD_ASSERT(...)
Definition: global_defs.h:131
Global macros to enhance readability and debugging, general constants.
std::vector< arma::mat::fixed< spacedim, dim > > jacobians
Jacobians of the mapping at the quadrature points.
Definition: fe_values.hh:74
FESystem(std::shared_ptr< FiniteElement< dim, spacedim > > fe, FEType t)
Constructor. FESystem for vector or tensor created from a scalar FE.
Definition: fe_system.cc:28
Compound finite element on dim dimensional simplex.
Definition: fe_system.hh:36
arma::vec::fixed< dim > basis_grad(const unsigned int i, const arma::vec::fixed< dim > &p, const unsigned int comp) const override
The vector variant of basis_grad must be implemented but need not be used.
Definition: fe_system.cc:161
Basic definitions of numerical quadrature rules.
Shape function gradients.
Definition: update_flags.hh:95
double basis_value(const unsigned int i, const arma::vec::fixed< dim > &p, const unsigned int comp) const override
The vector variant of basis_value must be implemented but need not be used.
Definition: fe_system.cc:146
std::vector< std::vector< arma::mat > > ref_shape_grads
Precomputed gradients of basis functions at the quadrature points.
Class FEValuesData holds the arrays of data computed by Mapping and FiniteElement.
Definition: fe_values.hh:48
const unsigned int size() const
Returns number of quadrature points.
Definition: quadrature.hh:139
std::vector< std::vector< double > > shape_values
Shape functions evaluated at the quadrature points.
Definition: fe_values.hh:94
std::vector< double > determinants
Determinants of Jacobians at quadrature points.
Definition: fe_values.hh:79
Structure for storing the precomputed finite element data.
std::vector< std::vector< arma::vec > > ref_shape_values
Precomputed values of basis functions at the quadrature points.
Abstract class for the description of a general finite element on a reference simplex in dim dimensio...
Definition: dofhandler.hh:30
std::vector< std::vector< arma::vec::fixed< spacedim > > > shape_gradients
Gradients of shape functions evaluated at the quadrature points.
Definition: fe_values.hh:101