Reference documentation for deal.II version 8.4.2
fe_q_bubbles.cc
1 // ---------------------------------------------------------------------
2 // @f$Id@f$
3 //
4 // Copyright (C) 2012 - 2015 by the deal.II authors
5 //
6 // This file is part of the deal.II library.
7 //
8 // The deal.II library is free software; you can use it, redistribute
9 // it, and/or modify it under the terms of the GNU Lesser General
10 // Public License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 // The full text of the license can be found in the file LICENSE at
13 // the top level of the deal.II distribution.
14 //
15 // ---------------------------------------------------------------------
16 
17 
18 #include <deal.II/base/quadrature.h>
19 #include <deal.II/base/qprojector.h>
20 #include <deal.II/base/template_constraints.h>
21 #include <deal.II/base/std_cxx11/unique_ptr.h>
22 #include <deal.II/fe/fe_q_bubbles.h>
23 #include <deal.II/fe/fe_nothing.h>
24 #include <deal.II/fe/fe_tools.h>
25 #include <deal.II/fe/fe_values.h>
26 #include <deal.II/fe/mapping_q1.h>
27 #include <deal.II/base/quadrature_lib.h>
28 #include <deal.II/dofs/dof_accessor.h>
29 #include <deal.II/dofs/dof_handler.h>
30 #include <deal.II/grid/tria.h>
31 
32 #include <deal.II/grid/grid_generator.h>
33 
34 
35 #include <vector>
36 #include <sstream>
37 
38 DEAL_II_NAMESPACE_OPEN
39 
40 
41 namespace FE_Q_Bubbles_Helper
42 {
43  namespace
44  {
45  template <int dim, int spacedim>
46  inline
47  void
49  std::vector<std::vector<FullMatrix<double> > > &matrices,
50  const bool isotropic_only)
51  {
52  const unsigned int dpc = fe.dofs_per_cell;
53  const unsigned int degree = fe.degree;
54 
55  // Initialize quadrature formula on fine cells
56  std_cxx11::unique_ptr<Quadrature<dim> > q_fine;
57  Quadrature<1> q_dummy(std::vector<Point<1> >(1), std::vector<double> (1,1.));
58  switch (dim)
59  {
60  case 1:
61  if (spacedim==1)
62  q_fine.reset(new QGauss<dim> (degree+1));
63  else if (spacedim==2)
64  q_fine.reset(new QAnisotropic<dim>(QGauss<1>(degree+1), q_dummy));
65  else
66  q_fine.reset(new QAnisotropic<dim>(QGauss<1>(degree+1), q_dummy, q_dummy));
67  break;
68  case 2:
69  if (spacedim==2)
70  q_fine.reset(new QGauss<dim> (degree+1));
71  else
72  q_fine.reset(new QAnisotropic<dim>(QGauss<1>(degree+1), QGauss<1>(degree+1), q_dummy));
73  break;
74  case 3:
75  q_fine.reset(new QGauss<dim> (degree+1));
76  break;
77  default:
78  AssertThrow(false, ExcInternalError());
79  }
80 
81  Assert(q_fine.get() != NULL, ExcInternalError());
82  const unsigned int nq = q_fine->size();
83 
84  // loop over all possible refinement cases
85  unsigned int ref_case = (isotropic_only)
88  for (; ref_case <= RefinementCase<dim>::isotropic_refinement; ++ref_case)
89  {
90  const unsigned int nc
92 
93  for (unsigned int i=0; i<nc; ++i)
94  {
95  Assert(matrices[ref_case-1][i].n() == dpc,
96  ExcDimensionMismatch(matrices[ref_case-1][i].n(),dpc));
97  Assert(matrices[ref_case-1][i].m() == dpc,
98  ExcDimensionMismatch(matrices[ref_case-1][i].m(),dpc));
99  }
100 
101  // create a respective refinement on the triangulation
103  GridGenerator::hyper_cube (tr, 0, 1);
104  tr.begin_active()->set_refine_flag(RefinementCase<dim>(ref_case));
106 
108  dh.distribute_dofs(fe);
109 
113 
114  const unsigned int n_dofs = dh.n_dofs();
115 
116  FullMatrix<double> fine_mass(n_dofs);
117  FullMatrix<double> coarse_rhs_matrix(n_dofs, dpc);
118 
119  std::vector<std::vector<types::global_dof_index> > child_ldi
120  (nc, std::vector<types::global_dof_index>(fe.dofs_per_cell));
121 
122  //now create the mass matrix and all the right_hand sides
123  unsigned int child_no = 0;
124  typename ::DoFHandler<dim>::active_cell_iterator cell
125  = dh.begin_active();
126  for (; cell!=dh.end(); ++cell, ++child_no)
127  {
128  fine.reinit(cell);
129  cell->get_dof_indices(child_ldi[child_no]);
130 
131  for (unsigned int q=0; q<nq; ++q)
132  for (unsigned int i=0; i<dpc; ++i)
133  for (unsigned int j=0; j<dpc; ++j)
134  {
135  const unsigned int gdi=child_ldi[child_no][i];
136  const unsigned int gdj=child_ldi[child_no][j];
137  fine_mass(gdi, gdj)+=fine.shape_value(i,q)
138  *fine.shape_value(j,q)
139  *fine.JxW(q);
140  Point<dim> quad_tmp;
141  for (unsigned int k=0; k<dim; ++k)
142  quad_tmp(k) = fine.quadrature_point(q)(k);
143  coarse_rhs_matrix(gdi, j)
144  +=fine.shape_value(i,q)
145  *fe.shape_value(j, quad_tmp)
146  *fine.JxW(q);
147  }
148  }
149 
150  //now solve for all right-hand sides simultaneously
151  ::FullMatrix<double> solution (n_dofs, dpc);
152  fine_mass.gauss_jordan();
153  fine_mass.mmult(solution, coarse_rhs_matrix);
154 
155  //and distribute to the fine cell matrices
156  for (unsigned int child_no=0; child_no<nc; ++child_no)
157  for (unsigned int i=0; i<dpc; ++i)
158  for (unsigned int j=0; j<dpc; ++j)
159  {
160  const unsigned int gdi=child_ldi[child_no][i];
161  //remove small entries
162  if (std::fabs(solution(gdi, j)) > 1.e-12)
163  matrices[ref_case-1][child_no](i,j)=solution(gdi, j);
164  }
165  }
166  }
167  }
168 }
169 
170 
171 template <int dim, int spacedim>
172 FE_Q_Bubbles<dim,spacedim>::FE_Q_Bubbles (const unsigned int q_degree)
173  :
174  FE_Q_Base<TensorProductPolynomialsBubbles<dim>, dim, spacedim> (
175  TensorProductPolynomialsBubbles<dim>(Polynomials::LagrangeEquidistant::generate_complete_basis(q_degree)),
176  FiniteElementData<dim>(get_dpo_vector(q_degree),
177  1, q_degree+1,
178  FiniteElementData<dim>::H1),
179  get_riaf_vector(q_degree)),
180  n_bubbles((q_degree<=1)?1:dim)
181 {
182  Assert (q_degree > 0,
183  ExcMessage ("This element can only be used for polynomial degrees "
184  "greater than zero"));
185 
186  std::vector<Point<1> > support_points_1d(q_degree+1);
187  for (unsigned int i=0; i<=q_degree; ++i)
188  support_points_1d[i][0] = static_cast<double>(i)/q_degree;
189 
190  this->initialize(support_points_1d);
191 
192  // adjust unit support point for discontinuous node
193  Point<dim> point;
194  for (unsigned int d=0; d<dim; ++d)
195  point[d] = 0.5;
196  for (unsigned int i=0; i<n_bubbles; ++i)
197  this->unit_support_points.push_back(point);
199 
201  if (dim == spacedim)
202  {
203  FE_Q_Bubbles_Helper::compute_embedding_matrices
204  (*this, this->prolongation, false);
205  // Fill restriction matrices with L2-projection
207  }
208 
209 }
210 
211 
212 
213 template <int dim, int spacedim>
215  :
216  FE_Q_Base<TensorProductPolynomialsBubbles<dim>, dim, spacedim> (
217  TensorProductPolynomialsBubbles<dim>(Polynomials::generate_complete_Lagrange_basis(points.get_points())),
218  FiniteElementData<dim>(get_dpo_vector(points.size()-1),
219  1, points.size(),
220  FiniteElementData<dim>::H1),
221  get_riaf_vector(points.size()-1)),
222  n_bubbles((points.size()-1<=1)?1:dim)
223 {
224  const unsigned int q_degree = points.size()-1;
225  (void) q_degree;
226  Assert (q_degree > 0,
227  ExcMessage ("This element can only be used for polynomial degrees "
228  "at least one"));
229 
230  this->initialize(points.get_points());
231 
232  // adjust unit support point for discontinuous node
233  Point<dim> point;
234  for (unsigned int d=0; d<dim; ++d)
235  point[d] = 0.5;
236  for (unsigned int i=0; i< n_bubbles; ++i)
237  this->unit_support_points.push_back(point);
239 
241  if (dim == spacedim)
242  {
243  FE_Q_Bubbles_Helper::compute_embedding_matrices
244  (*this, this->prolongation, false);
245  // Fill restriction matrices with L2-projection
247  }
248 }
249 
250 
251 
252 template <int dim, int spacedim>
253 std::string
255 {
256  // note that the FETools::get_fe_from_name function depends on the
257  // particular format of the string this function returns, so they have to be
258  // kept in synch
259 
260  std::ostringstream namebuf;
261  bool type = true;
262  const unsigned int n_points = this->degree;
263  std::vector<double> points(n_points);
264  const unsigned int dofs_per_cell = this->dofs_per_cell;
265  const std::vector<Point<dim> > &unit_support_points = this->unit_support_points;
266  unsigned int index = 0;
267 
268  // Decode the support points in one coordinate direction.
269  for (unsigned int j=0; j<dofs_per_cell; j++)
270  {
271  if ((dim>1) ? (unit_support_points[j](1)==0 &&
272  ((dim>2) ? unit_support_points[j](2)==0: true)) : true)
273  {
274  if (index == 0)
275  points[index] = unit_support_points[j](0);
276  else if (index == 1)
277  points[n_points-1] = unit_support_points[j](0);
278  else
279  points[index-1] = unit_support_points[j](0);
280 
281  index++;
282  }
283  }
284  // Do not consider the discontinuous node for dimension 1
285  Assert (index == n_points || (dim==1 && index == n_points+n_bubbles),
286  ExcMessage ("Could not decode support points in one coordinate direction."));
287 
288  // Check whether the support points are equidistant.
289  for (unsigned int j=0; j<n_points; j++)
290  if (std::fabs(points[j] - (double)j/(this->degree-1)) > 1e-15)
291  {
292  type = false;
293  break;
294  }
295 
296  if (type == true)
297  namebuf << "FE_Q_Bubbles<" << dim << ">(" << this->degree-1 << ")";
298  else
299  {
300 
301  // Check whether the support points come from QGaussLobatto.
302  const QGaussLobatto<1> points_gl(n_points);
303  type = true;
304  for (unsigned int j=0; j<n_points; j++)
305  if (points[j] != points_gl.point(j)(0))
306  {
307  type = false;
308  break;
309  }
310  if (type == true)
311  namebuf << "FE_Q_Bubbles<" << dim << ">(QGaussLobatto(" << this->degree << "))";
312  else
313  namebuf << "FE_Q_Bubbles<" << dim << ">(QUnknownNodes(" << this->degree-1 << "))";
314  }
315  return namebuf.str();
316 }
317 
318 
319 
320 template <int dim, int spacedim>
323 {
324  return new FE_Q_Bubbles<dim,spacedim>(*this);
325 }
326 
327 
328 
329 template <int dim, int spacedim>
330 void
331 FE_Q_Bubbles<dim,spacedim>::interpolate(std::vector<double> &local_dofs,
332  const std::vector<double> &values) const
333 {
334  Assert (values.size() == this->unit_support_points.size(),
335  ExcDimensionMismatch(values.size(),
336  this->unit_support_points.size()));
337  Assert (local_dofs.size() == this->dofs_per_cell,
338  ExcDimensionMismatch(local_dofs.size(),this->dofs_per_cell));
339  Assert (this->n_components() == 1,
340  ExcDimensionMismatch(this->n_components(), 1));
341 
342  std::copy(values.begin(), values.end(), local_dofs.begin());
343 
344  // We don't use the bubble functions for local interpolation
345  for (unsigned int i = 0; i<n_bubbles; ++i)
346  local_dofs[local_dofs.size()-i-1] = 0.;
347 }
348 
349 
350 
351 template <int dim, int spacedim>
352 void
353 FE_Q_Bubbles<dim,spacedim>::interpolate(std::vector<double> &local_dofs,
354  const std::vector<Vector<double> > &values,
355  unsigned int offset) const
356 {
357  Assert (values.size() == this->unit_support_points.size(),
358  ExcDimensionMismatch(values.size(),
359  this->unit_support_points.size()));
360  Assert (local_dofs.size() == this->dofs_per_cell,
361  ExcDimensionMismatch(local_dofs.size(),this->dofs_per_cell));
362  Assert (values[0].size() >= offset+this->n_components(),
363  ExcDimensionMismatch(values[0].size(),offset+this->n_components()));
364 
365  for (unsigned int i=0; i<this->dofs_per_cell-1; ++i)
366  {
367  const std::pair<unsigned int, unsigned int> index
368  = this->system_to_component_index(i);
369  local_dofs[i] = values[i](offset+index.first);
370  }
371 
372  // We don't use the bubble functions for local interpolation
373  for (unsigned int i = 0; i<n_bubbles; ++i)
374  local_dofs[local_dofs.size()-i-1] = 0.;
375 }
376 
377 
378 
379 template <int dim, int spacedim>
380 void
382  std::vector<double> &local_dofs,
383  const VectorSlice<const std::vector<std::vector<double> > > &values) const
384 {
385  Assert (values[0].size() == this->unit_support_points.size(),
386  ExcDimensionMismatch(values.size(),
387  this->unit_support_points.size()));
388  Assert (local_dofs.size() == this->dofs_per_cell,
389  ExcDimensionMismatch(local_dofs.size(),this->dofs_per_cell));
390  Assert (values.size() == this->n_components(),
391  ExcDimensionMismatch(values.size(), this->n_components()));
392 
393  for (unsigned int i=0; i<this->dofs_per_cell-1; ++i)
394  {
395  const std::pair<unsigned int, unsigned int> index
396  = this->system_to_component_index(i);
397  local_dofs[i] = values[index.first][i];
398  }
399 
400  // We don't use the bubble functions for local interpolation
401  for (unsigned int i = 0; i<n_bubbles; ++i)
402  local_dofs[local_dofs.size()-i-1] = 0.;
403 }
404 
405 
406 
407 template <int dim, int spacedim>
408 void
411  FullMatrix<double> &interpolation_matrix) const
412 {
413  // We don't know how to do this properly, yet.
414  // However, for SolutionTransfer to work we need to provide an implementation
415  // for the case that the x_source_fe is identical to this FE
416  typedef FE_Q_Bubbles<dim,spacedim> FEQBUBBLES;
417  typedef FiniteElement<dim,spacedim> FEL;
418 
419  AssertThrow ((x_source_fe.get_name().find ("FE_Q_Bubbles<") == 0)
420  ||
421  (dynamic_cast<const FEQBUBBLES *>(&x_source_fe) != 0)
422  ,
423  typename FEL::
424  ExcInterpolationNotImplemented());
425  Assert (interpolation_matrix.m() == this->dofs_per_cell,
426  ExcDimensionMismatch (interpolation_matrix.m(),
427  this->dofs_per_cell));
428  Assert (interpolation_matrix.n() == x_source_fe.dofs_per_cell,
429  ExcDimensionMismatch (interpolation_matrix.m(),
430  x_source_fe.dofs_per_cell));
431 
432  //Provide a short cut in case we are just inquiring the identity
433  if (dynamic_cast<const FEQBUBBLES *>(&x_source_fe)->degree == this->degree)
434  for (unsigned int i=0; i<interpolation_matrix.m(); ++i)
435  interpolation_matrix.set(i,i,1.);
436  //else we need to do more...
437  else
438  Assert(false, typename FEL::ExcInterpolationNotImplemented())
439  }
440 
441 
442 
443 template <int dim, int spacedim>
444 std::vector<bool>
446 {
447  unsigned int n_cont_dofs = Utilities::fixed_power<dim>(q_deg+1);
448  const unsigned int n_bubbles = (q_deg<=1?1:dim);
449  return std::vector<bool> (n_cont_dofs+n_bubbles,true);
450 }
451 
452 
453 
454 template <int dim, int spacedim>
455 std::vector<unsigned int>
457 {
458  std::vector<unsigned int> dpo(dim+1, 1U);
459  for (unsigned int i=1; i<dpo.size(); ++i)
460  dpo[i]=dpo[i-1]*(q_deg-1);
461 
462  dpo[dim]+=(q_deg<=1?1:dim);//all the bubble functions are discontinuous
463  return dpo;
464 }
465 
466 
467 
468 template <int dim, int spacedim>
469 bool
471 (const unsigned int shape_index,
472  const unsigned int face_index) const
473 {
474  // discontinuous functions have no support on faces
475  if (shape_index >= this->n_dofs_per_cell()-n_bubbles)
476  return false;
477  else
478  return FE_Q_Base<TensorProductPolynomialsBubbles<dim>,dim,spacedim>::has_support_on_face(shape_index, face_index);
479 }
480 
481 
482 
483 template <int dim, int spacedim>
484 const FullMatrix<double> &
486 (const unsigned int child,
487  const RefinementCase<dim> &refinement_case) const
488 {
490  ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
491  Assert (refinement_case!=RefinementCase<dim>::no_refinement,
492  ExcMessage("Prolongation matrices are only available for refined cells!"));
493  Assert (child<GeometryInfo<dim>::n_children(refinement_case),
494  ExcIndexRange(child,0,GeometryInfo<dim>::n_children(refinement_case)));
495 
496  Assert (this->prolongation[refinement_case-1][child].n() != 0,
497  ExcMessage("This prolongation matrix has not been computed yet!"));
498  // finally return the matrix
499  return this->prolongation[refinement_case-1][child];
500 }
501 
502 
503 
504 template <int dim, int spacedim>
505 const FullMatrix<double> &
507 (const unsigned int child,
508  const RefinementCase<dim> &refinement_case) const
509 {
511  ExcIndexRange(refinement_case,0,RefinementCase<dim>::isotropic_refinement+1));
512  Assert (refinement_case!=RefinementCase<dim>::no_refinement,
513  ExcMessage("Restriction matrices are only available for refined cells!"));
514  Assert (child<GeometryInfo<dim>::n_children(refinement_case),
515  ExcIndexRange(child,0,GeometryInfo<dim>::n_children(refinement_case)));
516 
517  Assert(this->restriction[refinement_case-1][child].n() != 0,
518  ExcMessage("This restriction matrix has not been computed yet!"));
519 
520  //finally return the matrix
521  return this->restriction[refinement_case-1][child];
522 }
523 
524 // explicit instantiations
525 #include "fe_q_bubbles.inst"
526 
527 DEAL_II_NAMESPACE_CLOSE
Transformed quadrature weights.
const unsigned int n_bubbles
Definition: fe_q_bubbles.h:195
Shape function values.
size_type m() const
std::vector< std::vector< FullMatrix< double > > > restriction
Definition: fe.h:2106
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1052
const std::vector< Point< dim > > & get_points() const
::ExceptionBase & ExcMessage(std::string arg1)
const unsigned int degree
Definition: fe_base.h:299
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
const Point< dim > & point(const unsigned int i) const
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: tria.cc:10397
void compute_embedding_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false, const double threshold=1.e-12)
Definition: fe_tools.cc:891
Transformed quadrature points.
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
Definition: point.h:89
std::vector< Point< dim > > unit_support_points
Definition: fe.h:2144
void set(const size_type i, const size_type j, const number value)
virtual void execute_coarsening_and_refinement()
Definition: tria.cc:11602
virtual const FullMatrix< double > & get_restriction_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case) const
static unsigned int n_children(const RefinementCase< dim > &refinement_case)
size_type n() const
std::vector< std::vector< FullMatrix< double > > > prolongation
Definition: fe.h:2120
#define Assert(cond, exc)
Definition: exceptions.h:294
virtual FiniteElement< dim, spacedim > * clone() const
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case) const
virtual void get_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const
virtual void interpolate(std::vector< double > &local_dofs, const std::vector< double > &values) const
virtual std::string get_name() const =0
virtual std::string get_name() const
unsigned int size() const
const unsigned int dofs_per_cell
Definition: fe_base.h:283
void initialize(const std::vector< Point< 1 > > &support_points_1d)
Definition: fe_q_base.cc:428
virtual double shape_value(const unsigned int i, const Point< dim > &p) const
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
Definition: fe.h:2742
unsigned int n_components() const
unsigned int n_dofs_per_cell() const
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const
static std::vector< bool > get_riaf_vector(const unsigned int degree)
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
Definition: fe.h:31
void compute_projection_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false)
Definition: fe_tools.cc:1117
void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false, const bool isotropic_prolongation_only=false)
Definition: fe.cc:278
FE_Q_Bubbles(const unsigned int p)