Flow123d
fe_rt.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id$
21  * $Revision$
22  * $LastChangedBy$
23  * $LastChangedDate$
24  *
25  * @file
26  * @brief Definitions of Raviart-Thomas finite elements.
27  * @author Jan Stebel
28  */
29 
30 #ifndef FE_RT_HH_
31 #define FE_RT_HH_
32 
33 #include "fem/finite_element.hh"
34 
35 
36 
37 /**
38  * @brief Raviart-Thomas element of order 0.
39  *
40  * The lowest order Raviart-Thomas finite element with linear basis functions
41  * and continuous normal components across element sides.
42  */
43 template <unsigned int dim, unsigned int spacedim>
44 class FE_RT0 : public FiniteElement<dim,spacedim>
45 {
55 
56 public:
57 
58  /// Number of raw basis functions.
59  static const unsigned int n_raw_functions = dim+1;
60 
61  /**
62  * @brief Constructor.
63  */
64  FE_RT0();
65 
66  /**
67  * @brief The scalar variant of basis_vector must be implemented but may not be used.
68  */
69  double basis_value(const unsigned int i, const arma::vec::fixed<dim> &p) const;
70 
71  /**
72  * @brief The scalar variant of basis_grad_vector must be implemented but may not be used.
73  */
74  arma::vec::fixed<dim> basis_grad(const unsigned int i, const arma::vec::fixed<dim> &p) const;
75 
76  /**
77  * @brief Returns the @p ith basis function evaluated at the point @p p.
78  * @param i Number of the basis function.
79  * @param p Point of evaluation.
80  */
81  arma::vec::fixed<dim> basis_vector(const unsigned int i, const arma::vec::fixed<dim> &p) const;
82 
83  /**
84  * @brief Returns the gradient of the @p ith basis function at the point @p p.
85  * @param i Number of the basis function.
86  * @param p Point of evaluation.
87  */
88  arma::mat::fixed<dim,dim> basis_grad_vector(const unsigned int i, const arma::vec::fixed<dim> &p) const;
89 
90  /**
91  * @brief Computes the conversion matrix from internal basis to shape functions.
92  *
93  * Initializes the @p node_matrix for computing the coefficients
94  * of the raw basis functions from values at support points.
95  * Since Raviart-Thomas element is not Lagrangean, the method has
96  * to be reimplemented.
97  */
98  void compute_node_matrix();
99 
100  /**
101  * @brief Calculates the data on the reference cell.
102  *
103  * @param q Quadrature.
104  * @param flags Flags that indicate what quantities should be calculated.
105  */
107 
108  /**
109  * @brief Decides which additional quantities have to be computed
110  * for each cell.
111  */
113 
114  /**
115  * @brief Computes the shape function values and gradients on the actual cell
116  * and fills the FEValues structure.
117  *
118  * @param q Quadrature.
119  * @param data The precomputed finite element data on the reference cell.
120  * @param fv_data The data to be computed.
121  */
122  virtual void fill_fe_values(const Quadrature<dim> &q,
123  FEInternalData &data,
124  FEValuesData<dim,spacedim> &fv_data);
125 
126 };
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 template<unsigned int dim, unsigned int spacedim>
139 {
140  arma::vec::fixed<dim> sp;
141 
142  this->init();
143 
144  number_of_dofs = dim+1;
145  number_of_single_dofs[dim] = dim+1;
146 
147  sp.fill(1./max(1.,(double)dim));
148  generalized_support_points.push_back(sp);
149  for (unsigned int i=0; i<dim; i++)
150  {
151  sp.fill(1./max(1.,(double)dim));
152  sp[i] = 0;
153  generalized_support_points.push_back(sp);
154  }
155 
156  order = 1;
157 
158  is_scalar_fe = false;
159 
160  compute_node_matrix();
161 }
162 
163 template<unsigned int dim, unsigned int spacedim>
164 double FE_RT0<dim,spacedim>::basis_value(const unsigned int i, const arma::vec::fixed<dim> &p) const
165 {
166  ASSERT(false, "basis_value() may not be called for vectorial finite element.");
167 
168  return 0.0;
169 }
170 
171 template<unsigned int dim, unsigned int spacedim>
172 arma::vec::fixed<dim> FE_RT0<dim,spacedim>::basis_grad(const unsigned int i, const arma::vec::fixed<dim> &p) const
173 {
174  ASSERT(false, "basis_grad() may not be called for vectorial finite element.");
175 }
176 
177 template<unsigned int dim, unsigned int spacedim>
178 arma::vec::fixed<dim> FE_RT0<dim,spacedim>::basis_vector(const unsigned int i, const arma::vec::fixed<dim> &p) const
179 {
180  ASSERT(i<n_raw_functions, "Index of basis function is out of range.");
181 
182  arma::vec::fixed<dim> v(p);
183 
184  if (i > 0)
185  v[i-1] -= 1;
186 
187  return v;
188 }
189 
190 template<unsigned int dim, unsigned int spacedim>
191 arma::mat::fixed<dim,dim> FE_RT0<dim,spacedim>::basis_grad_vector(const unsigned int i, const arma::vec::fixed<dim> &p) const
192 {
193  ASSERT(i<n_raw_functions, "Index of basis function is out of range.");
194 
195  return arma::eye(dim,dim);
196 }
197 
198 template<unsigned int dim, unsigned int spacedim>
200 {
201  arma::mat::fixed<n_raw_functions,dim+1> F;
202  arma::vec::fixed<dim> r;
203 
204  /*
205  * Node matrix helps creating the shape functions $\{b_k\}$ from
206  * the raw basis $\{r_i\}$:
207  *
208  * $$ b_k = \sum_{i=0}^{dim*(dim+1)-1} N_{ki} r_i. $$
209  *
210  * The shape functions must obey the flux condition
211  *
212  * $$ b_k\cdot n_j |\Gamma_j| = \delta_{kj}, $$
213  *
214  * where $n_j$, $|\Gamma_j|$ is the unit outward normal vector and
215  * the area of the $j$-th side, respectively. Consequently,
216  * the node matrix $N$ is determined as the Moon-Penrose
217  * pseudoinverse of the flux matrix, i.e.:
218  *
219  * $$ NF = I,\quad F_{ij} = r_i\cdot n_j |\Gamma_j|. $$
220  *
221  */
222 
223  for (unsigned int i=0; i<n_raw_functions; i++)
224  {
225  /*
226  * For the 0-th side we have:
227  *
228  * $$ |\Gamma_0| = \frac{\sqrt{dim}}{dim-1}, $$
229  * $$ n_0 = \frac{\sqrt{dim}}{dim}(1,\ldots,1). $$
230  *
231  * If dim==1, we set |\Gamma_0| = 1.
232  *
233  */
234 
235  r = basis_vector(i,generalized_support_points[0]);
236  if (dim == 1)
237  {
238  F(i,0) = sum(r);
239  }
240  else
241  {
242  F(i,0) = sum(r)/(1.*dim-1);
243  }
244 
245  /*
246  * For the remaining sides:
247  *
248  * $$ |\Gamma_j| = \sqrt(dim-1), $$
249  * $$ (n_j)_l = -\delta_{jl}. $$
250  *
251  * If dim==1, we set |\Gamma_1| = 1.
252  *
253  */
254 
255  if (dim == 1)
256  {
257  r = basis_vector(i,generalized_support_points[1]);
258  F(i,1) = -r(0);
259  }
260  else
261  {
262  for (unsigned int j=1; j<dim+1; j++)
263  {
264  r = basis_vector(i,generalized_support_points[j]);
265  F(i,j) = -r(j-1)/(1.*dim-1);
266  }
267  }
268  }
269 
270  if (dim>0) node_matrix = inv(F);
271 
272 }
273 
274 template<unsigned int dim, unsigned int spacedim>
276 {
277  FEInternalData *data = new FEInternalData;
278 
279  if (flags & update_values)
280  {
281  arma::mat::fixed<n_raw_functions,dim> raw_values;
282  arma::mat::fixed<dim+1,dim> shape_values;
283  vector<arma::vec> values;
284 
285  data->basis_vectors.resize(q.size());
286  values.resize(dim+1);
287  for (unsigned int i=0; i<q.size(); i++)
288  {
289  for (unsigned int j=0; j<n_raw_functions; j++)
290  raw_values.row(j) = trans(basis_vector(j, q.point(i)));
291 
292  shape_values = node_matrix * raw_values;
293 
294  for (unsigned int j=0; j<dim+1; j++)
295  values[j] = trans(shape_values.row(j));
296 
297  data->basis_vectors[i] = values;
298  }
299  }
300 
301  if (flags & update_gradients)
302  {
303  arma::mat::fixed<dim,dim> grad;
304  arma::mat::fixed<dim,dim> shape_grads;
305  vector<arma::mat> grads;
306 
307  data->basis_grad_vectors.resize(q.size());
308  grads.resize(dim+1);
309  for (unsigned int i=0; i<q.size(); i++)
310  {
311  for (unsigned int k=0; k<dim+1; k++)
312  {
313  grad.zeros();
314  for (unsigned int l=0; l<n_raw_functions; l++)
315  grad += basis_grad_vector(l, q.point(i)) * node_matrix(k,l);
316  grads[k] = grad;
317  }
318 
319  data->basis_grad_vectors[i] = grads;
320  }
321  }
322 
323  return data;
324 }
325 
326 template<unsigned int dim, unsigned int spacedim> inline
328 {
329  UpdateFlags f = flags;
330 
331  if (flags & update_values)
333 
334  if (flags & update_gradients)
336 
337  return f;
338 }
339 
340 template<unsigned int dim, unsigned int spacedim> inline
342  const Quadrature<dim> &q,
343  FEInternalData &data,
345 {
346  // shape values
347  if (fv_data.update_flags & update_values)
348  {
349  vector<arma::vec::fixed<spacedim> > vectors;
350  vectors.resize(dim+1);
351  for (unsigned int i = 0; i < q.size(); i++)
352  {
353  for (unsigned int k=0; k<dim+1; k++)
354  vectors[k] = fv_data.jacobians[i]*data.basis_vectors[i][k]/fv_data.determinants[i];
355 
356  fv_data.shape_vectors[i] = vectors;
357  }
358  }
359 
360  // shape gradients
361  if (fv_data.update_flags & update_gradients)
362  {
363  vector<arma::mat::fixed<spacedim,spacedim> > grads;
364  grads.resize(dim+1);
365  for (unsigned int i = 0; i < q.size(); i++)
366  {
367  for (unsigned int k=0; k<dim+1; k++)
368  grads[k] = fv_data.jacobians[i]*data.basis_grad_vectors[i][k]*fv_data.inverse_jacobians[i]/fv_data.determinants[i];
369 
370  fv_data.shape_grad_vectors[i] = grads;
371  }
372  }
373 }
374 
375 
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 #endif /* FE_RT_HH_ */