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