Reference documentation for deal.II version 9.1.0-pre
fe_q_base.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 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/polynomials_piecewise.h>
18 #include <deal.II/base/qprojector.h>
19 #include <deal.II/base/quadrature.h>
20 #include <deal.II/base/quadrature_lib.h>
21 #include <deal.II/base/std_cxx14/memory.h>
22 #include <deal.II/base/template_constraints.h>
23 #include <deal.II/base/tensor_product_polynomials.h>
24 #include <deal.II/base/tensor_product_polynomials_bubbles.h>
25 #include <deal.II/base/tensor_product_polynomials_const.h>
26 
27 #include <deal.II/fe/fe_dgp.h>
28 #include <deal.II/fe/fe_dgq.h>
29 #include <deal.II/fe/fe_nothing.h>
30 #include <deal.II/fe/fe_q_base.h>
31 #include <deal.II/fe/fe_tools.h>
32 
33 #include <sstream>
34 #include <vector>
35 
36 DEAL_II_NAMESPACE_OPEN
37 
38 
39 namespace internal
40 {
41  namespace FE_Q_Base
42  {
43  namespace
44  {
45  // get the renumbering for faces
46  template <int dim>
47  inline std::vector<unsigned int>
48  face_lexicographic_to_hierarchic_numbering(const unsigned int degree)
49  {
50  std::vector<unsigned int> dpo(dim, 1U);
51  for (unsigned int i = 1; i < dpo.size(); ++i)
52  dpo[i] = dpo[i - 1] * (degree - 1);
53  const ::FiniteElementData<dim - 1> face_data(dpo, 1, degree);
54  std::vector<unsigned int> face_renumber(face_data.dofs_per_cell);
56  face_renumber);
57  return face_renumber;
58  }
59 
60  // dummy specialization for dim == 1 to avoid linker errors
61  template <>
62  inline std::vector<unsigned int>
63  face_lexicographic_to_hierarchic_numbering<1>(const unsigned int)
64  {
65  return std::vector<unsigned int>();
66  }
67 
68 
69 
70  // in get_restriction_matrix() and get_prolongation_matrix(), want to undo
71  // tensorization on inner loops for performance reasons. this clears a
72  // dim-array
73  template <int dim>
74  inline void
75  zero_indices(unsigned int (&indices)[dim])
76  {
77  for (unsigned int d = 0; d < dim; ++d)
78  indices[d] = 0;
79  }
80 
81 
82 
83  // in get_restriction_matrix() and get_prolongation_matrix(), want to undo
84  // tensorization on inner loops for performance reasons. this increments
85  // tensor product indices
86  template <int dim>
87  inline void
88  increment_indices(unsigned int (&indices)[dim], const unsigned int dofs1d)
89  {
90  ++indices[0];
91  for (int d = 0; d < dim - 1; ++d)
92  if (indices[d] == dofs1d)
93  {
94  indices[d] = 0;
95  indices[d + 1]++;
96  }
97  }
98  } // namespace
99  } // namespace FE_Q_Base
100 } // namespace internal
101 
102 
103 
108 template <class PolynomialType, int xdim, int xspacedim>
109 struct FE_Q_Base<PolynomialType, xdim, xspacedim>::Implementation
110 {
115  template <int spacedim>
116  static void
117  initialize_constraints(const std::vector<Point<1>> &,
119  {
120  // no constraints in 1d
121  }
122 
123 
124  template <int spacedim>
125  static void
126  initialize_constraints(const std::vector<Point<1>> & /*points*/,
128  {
129  const unsigned int dim = 2;
130 
131  unsigned int q_deg = fe.degree;
132  if (std::is_same<PolynomialType,
134  q_deg = fe.degree - 1;
135 
136  // restricted to each face, the traces of the shape functions is an
137  // element of P_{k} (in 2d), or Q_{k} (in 3d), where k is the degree of
138  // the element. from this, we interpolate between mother and cell face.
139 
140  // the interpolation process works as follows: on each subface, we want
141  // that finite element solutions from both sides coincide. i.e. if a and b
142  // are expansion coefficients for the shape functions from both sides, we
143  // seek a relation between a and b such that
144  // sum_j a_j phi^c_j(x) == sum_j b_j phi_j(x)
145  // for all points x on the interface. here, phi^c_j are the shape
146  // functions on the small cell on one side of the face, and phi_j those on
147  // the big cell on the other side. To get this relation, it suffices to
148  // look at a sufficient number of points for which this has to hold. if
149  // there are n functions, then we need n evaluation points, and we choose
150  // them equidistantly.
151  //
152  // we obtain the matrix system
153  // A a == B b
154  // where
155  // A_ij = phi^c_j(x_i)
156  // B_ij = phi_j(x_i)
157  // and the relation we are looking for is
158  // a = A^-1 B b
159  //
160  // for the special case of Lagrange interpolation polynomials, A_ij
161  // reduces to delta_ij, and
162  // a_i = B_ij b_j
163  // Hence, interface_constraints(i,j)=B_ij.
164  //
165  // for the general case, where we don't have Lagrange interpolation
166  // polynomials, this is a little more complicated. Then we would evaluate
167  // at a number of points and invert the interpolation matrix A.
168  //
169  // Note, that we build up these matrices for all subfaces at once, rather
170  // than considering them separately. the reason is that we finally will
171  // want to have them in this order anyway, as this is the format we need
172  // inside deal.II
173 
174  // In the following the points x_i are constructed in following order
175  // (n=degree-1)
176  // *----------*---------*
177  // 1..n 0 n+1..2n
178  // i.e. first the midpoint of the line, then the support points on subface
179  // 0 and on subface 1
180  std::vector<Point<dim - 1>> constraint_points;
181  // Add midpoint
182  constraint_points.emplace_back(0.5);
183 
184  if (q_deg > 1)
185  {
186  const unsigned int n = q_deg - 1;
187  const double step = 1. / q_deg;
188  // subface 0
189  for (unsigned int i = 1; i <= n; ++i)
190  constraint_points.push_back(
192  Point<dim - 1>(i * step), 0));
193  // subface 1
194  for (unsigned int i = 1; i <= n; ++i)
195  constraint_points.push_back(
197  Point<dim - 1>(i * step), 1));
198  }
199 
200  // Now construct relation between destination (child) and source (mother)
201  // dofs.
202 
203  fe.interface_constraints.TableBase<2, double>::reinit(
205 
206  // use that the element evaluates to 1 at index 0 and along the line at
207  // zero
208  const std::vector<unsigned int> &index_map_inverse =
209  fe.poly_space.get_numbering_inverse();
210  const std::vector<unsigned int> face_index_map =
211  internal::FE_Q_Base::face_lexicographic_to_hierarchic_numbering<dim>(
212  q_deg);
213  Assert(std::abs(
214  fe.poly_space.compute_value(index_map_inverse[0], Point<dim>()) -
215  1.) < 1e-14,
216  ExcInternalError());
217 
218  for (unsigned int i = 0; i < constraint_points.size(); ++i)
219  for (unsigned int j = 0; j < q_deg + 1; ++j)
220  {
221  Point<dim> p;
222  p[0] = constraint_points[i](0);
223  fe.interface_constraints(i, face_index_map[j]) =
224  fe.poly_space.compute_value(index_map_inverse[j], p);
225 
226  // if the value is small up to round-off, then simply set it to zero
227  // to avoid unwanted fill-in of the constraint matrices (which would
228  // then increase the number of other DoFs a constrained DoF would
229  // couple to)
230  if (std::fabs(fe.interface_constraints(i, face_index_map[j])) < 1e-13)
231  fe.interface_constraints(i, face_index_map[j]) = 0;
232  }
233  }
234 
235 
236  template <int spacedim>
237  static void
238  initialize_constraints(const std::vector<Point<1>> & /*points*/,
240  {
241  const unsigned int dim = 3;
242 
243  unsigned int q_deg = fe.degree;
244  if (std::is_same<PolynomialType,
246  q_deg = fe.degree - 1;
247 
248  // For a detailed documentation of the interpolation see the
249  // FE_Q_Base<2>::initialize_constraints function.
250 
251  // In the following the points x_i are constructed in the order as
252  // described in the documentation of the FiniteElement class (fe_base.h),
253  // i.e.
254  // *--15--4--16--*
255  // | | |
256  // 10 19 6 20 12
257  // | | |
258  // 1--7---0--8---2
259  // | | |
260  // 9 17 5 18 11
261  // | | |
262  // *--13--3--14--*
263  std::vector<Point<dim - 1>> constraint_points;
264 
265  // Add midpoint
266  constraint_points.emplace_back(0.5, 0.5);
267 
268  // Add midpoints of lines of "mother-face"
269  constraint_points.emplace_back(0, 0.5);
270  constraint_points.emplace_back(1, 0.5);
271  constraint_points.emplace_back(0.5, 0);
272  constraint_points.emplace_back(0.5, 1);
273 
274  if (q_deg > 1)
275  {
276  const unsigned int n = q_deg - 1;
277  const double step = 1. / q_deg;
278  std::vector<Point<dim - 2>> line_support_points(n);
279  for (unsigned int i = 0; i < n; ++i)
280  line_support_points[i](0) = (i + 1) * step;
281  Quadrature<dim - 2> qline(line_support_points);
282 
283  // auxiliary points in 2d
284  std::vector<Point<dim - 1>> p_line(n);
285 
286  // Add nodes of lines interior in the "mother-face"
287 
288  // line 5: use line 9
289  QProjector<dim - 1>::project_to_subface(qline, 0, 0, p_line);
290  for (unsigned int i = 0; i < n; ++i)
291  constraint_points.push_back(p_line[i] + Point<dim - 1>(0.5, 0));
292  // line 6: use line 10
293  QProjector<dim - 1>::project_to_subface(qline, 0, 1, p_line);
294  for (unsigned int i = 0; i < n; ++i)
295  constraint_points.push_back(p_line[i] + Point<dim - 1>(0.5, 0));
296  // line 7: use line 13
297  QProjector<dim - 1>::project_to_subface(qline, 2, 0, p_line);
298  for (unsigned int i = 0; i < n; ++i)
299  constraint_points.push_back(p_line[i] + Point<dim - 1>(0, 0.5));
300  // line 8: use line 14
301  QProjector<dim - 1>::project_to_subface(qline, 2, 1, p_line);
302  for (unsigned int i = 0; i < n; ++i)
303  constraint_points.push_back(p_line[i] + Point<dim - 1>(0, 0.5));
304 
305  // DoFs on bordering lines lines 9-16
306  for (unsigned int face = 0;
307  face < GeometryInfo<dim - 1>::faces_per_cell;
308  ++face)
309  for (unsigned int subface = 0;
310  subface < GeometryInfo<dim - 1>::max_children_per_face;
311  ++subface)
312  {
314  face,
315  subface,
316  p_line);
317  constraint_points.insert(constraint_points.end(),
318  p_line.begin(),
319  p_line.end());
320  }
321 
322  // Create constraints for interior nodes
323  std::vector<Point<dim - 1>> inner_points(n * n);
324  for (unsigned int i = 0, iy = 1; iy <= n; ++iy)
325  for (unsigned int ix = 1; ix <= n; ++ix)
326  inner_points[i++] = Point<dim - 1>(ix * step, iy * step);
327 
328  // at the moment do this for isotropic face refinement only
329  for (unsigned int child = 0;
330  child < GeometryInfo<dim - 1>::max_children_per_cell;
331  ++child)
332  for (unsigned int i = 0; i < inner_points.size(); ++i)
333  constraint_points.push_back(
335  child));
336  }
337 
338  // Now construct relation between destination (child) and source (mother)
339  // dofs.
340  const unsigned int pnts = (q_deg + 1) * (q_deg + 1);
341 
342  // use that the element evaluates to 1 at index 0 and along the line at
343  // zero
344  const std::vector<unsigned int> &index_map_inverse =
345  fe.poly_space.get_numbering_inverse();
346  const std::vector<unsigned int> face_index_map =
347  internal::FE_Q_Base::face_lexicographic_to_hierarchic_numbering<dim>(
348  q_deg);
349  Assert(std::abs(
350  fe.poly_space.compute_value(index_map_inverse[0], Point<dim>()) -
351  1.) < 1e-14,
352  ExcInternalError());
353 
354  fe.interface_constraints.TableBase<2, double>::reinit(
356 
357  for (unsigned int i = 0; i < constraint_points.size(); ++i)
358  {
359  const double interval = (double)(q_deg * 2);
360  bool mirror[dim - 1];
361  Point<dim> constraint_point;
362 
363  // Eliminate FP errors in constraint points. Due to their origin, they
364  // must all be fractions of the unit interval. If we have polynomial
365  // degree 4, the refined element has 8 intervals. Hence the
366  // coordinates must be 0, 0.125, 0.25, 0.375 etc. Now the coordinates
367  // of the constraint points will be multiplied by the inverse of the
368  // interval size (in the example by 8). After that the coordinates
369  // must be integral numbers. Hence a normal truncation is performed
370  // and the coordinates will be scaled back. The equal treatment of all
371  // coordinates should eliminate any FP errors.
372  for (unsigned int k = 0; k < dim - 1; ++k)
373  {
374  const int coord_int =
375  static_cast<int>(constraint_points[i](k) * interval + 0.25);
376  constraint_point(k) = 1. * coord_int / interval;
377 
378  // The following lines of code should eliminate the problems with
379  // the Constraint-Matrix, which appeared for P>=4. The
380  // AffineConstraints class complained about different constraints
381  // for the same entry of the Constraint-Matrix. Actually this
382  // difference could be attributed to FP errors, as it was in the
383  // range of 1.0e-16. These errors originate in the loss of
384  // symmetry in the FP approximation of the shape-functions.
385  // Considering a 3rd order shape function in 1D, we have
386  // N0(x)=N3(1-x) and N1(x)=N2(1-x). For higher order polynomials
387  // the FP approximations of the shape functions do not satisfy
388  // these equations any more! Thus in the following code
389  // everything is computed in the interval x \in [0..0.5], which is
390  // sufficient to express all values that could come out from a
391  // computation of any shape function in the full interval
392  // [0..1]. If x > 0.5 the computation is done for 1-x with the
393  // shape function N_{p-n} instead of N_n. Hence symmetry is
394  // preserved and everything works fine...
395  //
396  // For a different explanation of the problem, see the discussion
397  // in the FiniteElement class for constraint matrices in 3d.
398  mirror[k] = (constraint_point(k) > 0.5);
399  if (mirror[k])
400  constraint_point(k) = 1.0 - constraint_point(k);
401  }
402 
403  for (unsigned int j = 0; j < pnts; ++j)
404  {
405  unsigned int indices[2] = {j % (q_deg + 1), j / (q_deg + 1)};
406 
407  for (unsigned int k = 0; k < 2; ++k)
408  if (mirror[k])
409  indices[k] = q_deg - indices[k];
410 
411  const unsigned int new_index =
412  indices[1] * (q_deg + 1) + indices[0];
413 
414  fe.interface_constraints(i, face_index_map[j]) =
415  fe.poly_space.compute_value(index_map_inverse[new_index],
416  constraint_point);
417 
418  // if the value is small up to round-off, then simply set it to
419  // zero to avoid unwanted fill-in of the constraint matrices
420  // (which would then increase the number of other DoFs a
421  // constrained DoF would couple to)
422  if (std::fabs(fe.interface_constraints(i, face_index_map[j])) <
423  1e-13)
424  fe.interface_constraints(i, face_index_map[j]) = 0;
425  }
426  }
427  }
428 };
429 
430 
431 
432 template <class PolynomialType, int dim, int spacedim>
434  const PolynomialType & poly_space,
435  const FiniteElementData<dim> &fe_data,
436  const std::vector<bool> & restriction_is_additive_flags)
437  : FE_Poly<PolynomialType, dim, spacedim>(
438  poly_space,
439  fe_data,
440  restriction_is_additive_flags,
441  std::vector<ComponentMask>(1, std::vector<bool>(1, true)))
442  , q_degree(std::is_same<PolynomialType,
443  TensorProductPolynomialsBubbles<dim>>::value ?
444  this->degree - 1 :
445  this->degree)
446 {}
447 
448 
449 
450 template <class PolynomialType, int dim, int spacedim>
451 void
453  const std::vector<Point<1>> &points)
454 {
455  Assert(points[0][0] == 0,
456  ExcMessage("The first support point has to be zero."));
457  Assert(points.back()[0] == 1,
458  ExcMessage("The last support point has to be one."));
459 
460  // distinguish q/q_dg0 case: need to be flexible enough to allow more
461  // degrees of freedom than there are FE_Q degrees of freedom for derived
462  // class FE_Q_DG0 that otherwise shares 95% of the code.
463  const unsigned int q_dofs_per_cell =
464  Utilities::fixed_power<dim>(q_degree + 1);
465  Assert(q_dofs_per_cell == this->dofs_per_cell ||
466  q_dofs_per_cell + 1 == this->dofs_per_cell ||
467  q_dofs_per_cell + dim == this->dofs_per_cell,
468  ExcInternalError());
469 
470  {
471  std::vector<unsigned int> renumber(q_dofs_per_cell);
472  const FiniteElementData<dim> fe(get_dpo_vector(q_degree), 1, q_degree);
474  for (unsigned int i = q_dofs_per_cell; i < this->dofs_per_cell; ++i)
475  renumber.push_back(i);
476  this->poly_space.set_numbering(renumber);
477  }
478 
479  // Finally fill in support points on cell and face and initialize
480  // constraints. All of this can happen in parallel
481  Threads::TaskGroup<> tasks;
482  tasks += Threads::new_task([&]() { initialize_unit_support_points(points); });
483  tasks +=
485  tasks += Threads::new_task([&]() { initialize_constraints(points); });
486  tasks +=
488  tasks.join_all();
489 
490  // do not initialize embedding and restriction here. these matrices are
491  // initialized on demand in get_restriction_matrix and
492  // get_prolongation_matrix
493 }
494 
495 
496 
497 template <class PolynomialType, int dim, int spacedim>
498 void
500  const FiniteElement<dim, spacedim> &x_source_fe,
501  FullMatrix<double> & interpolation_matrix) const
502 {
503  // go through the list of elements we can interpolate from
504  if (const FE_Q_Base<PolynomialType, dim, spacedim> *source_fe =
505  dynamic_cast<const FE_Q_Base<PolynomialType, dim, spacedim> *>(
506  &x_source_fe))
507  {
508  // ok, source is a Q element, so we will be able to do the work
509  Assert(interpolation_matrix.m() == this->dofs_per_cell,
510  ExcDimensionMismatch(interpolation_matrix.m(),
511  this->dofs_per_cell));
512  Assert(interpolation_matrix.n() == x_source_fe.dofs_per_cell,
513  ExcDimensionMismatch(interpolation_matrix.m(),
514  x_source_fe.dofs_per_cell));
515 
516  // only evaluate Q dofs
517  const unsigned int q_dofs_per_cell =
518  Utilities::fixed_power<dim>(q_degree + 1);
519  const unsigned int source_q_dofs_per_cell =
520  Utilities::fixed_power<dim>(source_fe->degree + 1);
521 
522  // evaluation is simply done by evaluating the other FE's basis functions
523  // on the unit support points (FE_Q has the property that the cell
524  // interpolation matrix is a unit matrix, so no need to evaluate it and
525  // invert it)
526  for (unsigned int j = 0; j < q_dofs_per_cell; ++j)
527  {
528  // read in a point on this cell and evaluate the shape functions there
529  const Point<dim> p = this->unit_support_points[j];
530 
531  // FE_Q element evaluates to 1 in unit support point and to zero in
532  // all other points by construction
533  Assert(std::abs(this->poly_space.compute_value(j, p) - 1.) < 1e-13,
534  ExcInternalError());
535 
536  for (unsigned int i = 0; i < source_q_dofs_per_cell; ++i)
537  interpolation_matrix(j, i) =
538  source_fe->poly_space.compute_value(i, p);
539  }
540 
541  // for FE_Q_DG0, add one last row of identity
542  if (q_dofs_per_cell < this->dofs_per_cell)
543  {
544  AssertDimension(source_q_dofs_per_cell + 1, source_fe->dofs_per_cell);
545  for (unsigned int i = 0; i < source_q_dofs_per_cell; ++i)
546  interpolation_matrix(q_dofs_per_cell, i) = 0.;
547  for (unsigned int j = 0; j < q_dofs_per_cell; ++j)
548  interpolation_matrix(j, source_q_dofs_per_cell) = 0.;
549  interpolation_matrix(q_dofs_per_cell, source_q_dofs_per_cell) = 1.;
550  }
551 
552  // cut off very small values
553  const double eps = 2e-13 * q_degree * dim;
554  for (unsigned int i = 0; i < this->dofs_per_cell; ++i)
555  for (unsigned int j = 0; j < source_fe->dofs_per_cell; ++j)
556  if (std::fabs(interpolation_matrix(i, j)) < eps)
557  interpolation_matrix(i, j) = 0.;
558 
559  // make sure that the row sum of each of the matrices is 1 at this
560  // point. this must be so since the shape functions sum up to 1
561  for (unsigned int i = 0; i < this->dofs_per_cell; ++i)
562  {
563  double sum = 0.;
564  for (unsigned int j = 0; j < source_fe->dofs_per_cell; ++j)
565  sum += interpolation_matrix(i, j);
566 
567  Assert(std::fabs(sum - 1) < eps, ExcInternalError());
568  }
569  }
570  else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe))
571  {
572  // the element we want to interpolate from is an FE_Nothing. this
573  // element represents a function that is constant zero and has no
574  // degrees of freedom, so the interpolation is simply a multiplication
575  // with a n_dofs x 0 matrix. there is nothing to do here
576 
577  // we would like to verify that the number of rows and columns of
578  // the matrix equals this->dofs_per_cell and zero. unfortunately,
579  // whenever we do FullMatrix::reinit(m,0), it sets both rows and
580  // columns to zero, instead of m and zero. thus, only test the
581  // number of columns
582  Assert(interpolation_matrix.n() == x_source_fe.dofs_per_cell,
583  ExcDimensionMismatch(interpolation_matrix.m(),
584  x_source_fe.dofs_per_cell));
585  }
586  else
587  AssertThrow(
588  false,
589  (typename FiniteElement<dim,
590  spacedim>::ExcInterpolationNotImplemented()));
591 }
592 
593 
594 
595 template <class PolynomialType, int dim, int spacedim>
596 void
598  const FiniteElement<dim, spacedim> &source_fe,
599  FullMatrix<double> & interpolation_matrix) const
600 {
601  Assert(dim > 1, ExcImpossibleInDim(1));
604  interpolation_matrix);
605 }
606 
607 
608 
609 template <class PolynomialType, int dim, int spacedim>
610 void
612  const FiniteElement<dim, spacedim> &x_source_fe,
613  const unsigned int subface,
614  FullMatrix<double> & interpolation_matrix) const
615 {
616  Assert(interpolation_matrix.m() == x_source_fe.dofs_per_face,
617  ExcDimensionMismatch(interpolation_matrix.m(),
618  x_source_fe.dofs_per_face));
619 
620  // see if source is a Q element
621  if (const FE_Q_Base<PolynomialType, dim, spacedim> *source_fe =
622  dynamic_cast<const FE_Q_Base<PolynomialType, dim, spacedim> *>(
623  &x_source_fe))
624  {
625  // have this test in here since a table of size 2x0 reports its size as
626  // 0x0
627  Assert(interpolation_matrix.n() == this->dofs_per_face,
628  ExcDimensionMismatch(interpolation_matrix.n(),
629  this->dofs_per_face));
630 
631  // Make sure that the element for which the DoFs should be constrained
632  // is the one with the higher polynomial degree. Actually the procedure
633  // will work also if this assertion is not satisfied. But the matrices
634  // produced in that case might lead to problems in the hp procedures,
635  // which use this method.
636  Assert(
637  this->dofs_per_face <= source_fe->dofs_per_face,
638  (typename FiniteElement<dim,
639  spacedim>::ExcInterpolationNotImplemented()));
640 
641  // generate a point on this cell and evaluate the shape functions there
642  const Quadrature<dim - 1> quad_face_support(
643  source_fe->get_unit_face_support_points());
644 
645  // Rule of thumb for FP accuracy, that can be expected for a given
646  // polynomial degree. This value is used to cut off values close to
647  // zero.
648  double eps = 2e-13 * q_degree * (dim - 1);
649 
650  // compute the interpolation matrix by simply taking the value at the
651  // support points.
652  // TODO: Verify that all faces are the same with respect to
653  // these support points. Furthermore, check if something has to
654  // be done for the face orientation flag in 3D.
655  const Quadrature<dim> subface_quadrature =
656  subface == numbers::invalid_unsigned_int ?
657  QProjector<dim>::project_to_face(quad_face_support, 0) :
658  QProjector<dim>::project_to_subface(quad_face_support, 0, subface);
659  for (unsigned int i = 0; i < source_fe->dofs_per_face; ++i)
660  {
661  const Point<dim> &p = subface_quadrature.point(i);
662 
663  for (unsigned int j = 0; j < this->dofs_per_face; ++j)
664  {
665  double matrix_entry =
666  this->shape_value(this->face_to_cell_index(j, 0), p);
667 
668  // Correct the interpolated value. I.e. if it is close to 1 or
669  // 0, make it exactly 1 or 0. Unfortunately, this is required to
670  // avoid problems with higher order elements.
671  if (std::fabs(matrix_entry - 1.0) < eps)
672  matrix_entry = 1.0;
673  if (std::fabs(matrix_entry) < eps)
674  matrix_entry = 0.0;
675 
676  interpolation_matrix(i, j) = matrix_entry;
677  }
678  }
679 
680  // make sure that the row sum of each of the matrices is 1 at this
681  // point. this must be so since the shape functions sum up to 1
682  for (unsigned int j = 0; j < source_fe->dofs_per_face; ++j)
683  {
684  double sum = 0.;
685 
686  for (unsigned int i = 0; i < this->dofs_per_face; ++i)
687  sum += interpolation_matrix(j, i);
688 
689  Assert(std::fabs(sum - 1) < eps, ExcInternalError());
690  }
691  }
692  else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != nullptr)
693  {
694  // nothing to do here, the FE_Nothing has no degrees of freedom anyway
695  }
696  else
697  AssertThrow(
698  false,
699  (typename FiniteElement<dim,
700  spacedim>::ExcInterpolationNotImplemented()));
701 }
702 
703 
704 
705 template <class PolynomialType, int dim, int spacedim>
706 bool
708 {
709  return true;
710 }
711 
712 
713 
714 template <class PolynomialType, int dim, int spacedim>
715 std::vector<std::pair<unsigned int, unsigned int>>
717  const FiniteElement<dim, spacedim> &fe_other) const
718 {
719  // we can presently only compute these identities if both FEs are FE_Qs or
720  // if the other one is an FE_Nothing. in the first case, there should be
721  // exactly one single DoF of each FE at a vertex, and they should have
722  // identical value
723  if (dynamic_cast<const FE_Q_Base<PolynomialType, dim, spacedim> *>(
724  &fe_other) != nullptr)
725  {
726  return std::vector<std::pair<unsigned int, unsigned int>>(
727  1, std::make_pair(0U, 0U));
728  }
729  else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
730  {
731  // the FE_Nothing has no degrees of freedom, so there are no
732  // equivalencies to be recorded
733  return std::vector<std::pair<unsigned int, unsigned int>>();
734  }
735  else if (fe_other.dofs_per_face == 0)
736  {
737  // if the other element has no elements on faces at all,
738  // then it would be impossible to enforce any kind of
739  // continuity even if we knew exactly what kind of element
740  // we have -- simply because the other element declares
741  // that it is discontinuous because it has no DoFs on
742  // its faces. in that case, just state that we have no
743  // constraints to declare
744  return std::vector<std::pair<unsigned int, unsigned int>>();
745  }
746  else
747  {
748  Assert(false, ExcNotImplemented());
749  return std::vector<std::pair<unsigned int, unsigned int>>();
750  }
751 }
752 
753 
754 
755 template <class PolynomialType, int dim, int spacedim>
756 std::vector<std::pair<unsigned int, unsigned int>>
758  const FiniteElement<dim, spacedim> &fe_other) const
759 {
760  // we can presently only compute these identities if both FEs are FE_Qs or
761  // if the other one is an FE_Nothing
762  if (const FE_Q_Base<PolynomialType, dim, spacedim> *fe_q_other =
763  dynamic_cast<const FE_Q_Base<PolynomialType, dim, spacedim> *>(
764  &fe_other))
765  {
766  // dofs are located along lines, so two dofs are identical if they are
767  // located at identical positions. if we had only equidistant points, we
768  // could simply check for similarity like (i+1)*q == (j+1)*p, but we
769  // might have other support points (e.g. Gauss-Lobatto
770  // points). Therefore, read the points in unit_support_points for the
771  // first coordinate direction. We take the lexicographic ordering of the
772  // points in the first direction (i.e., x-direction), which we access
773  // between index 1 and p-1 (index 0 and p are vertex dofs).
774  const unsigned int p = this->degree;
775  const unsigned int q = fe_q_other->degree;
776 
777  std::vector<std::pair<unsigned int, unsigned int>> identities;
778 
779  const std::vector<unsigned int> &index_map_inverse =
780  this->poly_space.get_numbering_inverse();
781  const std::vector<unsigned int> &index_map_inverse_other =
782  fe_q_other->poly_space.get_numbering_inverse();
783 
784  for (unsigned int i = 0; i < p - 1; ++i)
785  for (unsigned int j = 0; j < q - 1; ++j)
786  if (std::fabs(
787  this->unit_support_points[index_map_inverse[i + 1]][0] -
788  fe_q_other->unit_support_points[index_map_inverse_other[j + 1]]
789  [0]) < 1e-14)
790  identities.emplace_back(i, j);
791 
792  return identities;
793  }
794  else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
795  {
796  // the FE_Nothing has no degrees of freedom, so there are no
797  // equivalencies to be recorded
798  return std::vector<std::pair<unsigned int, unsigned int>>();
799  }
800  else if (fe_other.dofs_per_face == 0)
801  {
802  // if the other element has no elements on faces at all,
803  // then it would be impossible to enforce any kind of
804  // continuity even if we knew exactly what kind of element
805  // we have -- simply because the other element declares
806  // that it is discontinuous because it has no DoFs on
807  // its faces. in that case, just state that we have no
808  // constraints to declare
809  return std::vector<std::pair<unsigned int, unsigned int>>();
810  }
811  else
812  {
813  Assert(false, ExcNotImplemented());
814  return std::vector<std::pair<unsigned int, unsigned int>>();
815  }
816 }
817 
818 
819 
820 template <class PolynomialType, int dim, int spacedim>
821 std::vector<std::pair<unsigned int, unsigned int>>
823  const FiniteElement<dim, spacedim> &fe_other) const
824 {
825  // we can presently only compute these identities if both FEs are FE_Qs or
826  // if the other one is an FE_Nothing
827  if (const FE_Q_Base<PolynomialType, dim, spacedim> *fe_q_other =
828  dynamic_cast<const FE_Q_Base<PolynomialType, dim, spacedim> *>(
829  &fe_other))
830  {
831  // this works exactly like the line case above, except that now we have
832  // to have two indices i1, i2 and j1, j2 to characterize the dofs on the
833  // face of each of the finite elements. since they are ordered
834  // lexicographically along the first line and we have a tensor product,
835  // the rest is rather straightforward
836  const unsigned int p = this->degree;
837  const unsigned int q = fe_q_other->degree;
838 
839  std::vector<std::pair<unsigned int, unsigned int>> identities;
840 
841  const std::vector<unsigned int> &index_map_inverse =
842  this->poly_space.get_numbering_inverse();
843  const std::vector<unsigned int> &index_map_inverse_other =
844  fe_q_other->poly_space.get_numbering_inverse();
845 
846  for (unsigned int i1 = 0; i1 < p - 1; ++i1)
847  for (unsigned int i2 = 0; i2 < p - 1; ++i2)
848  for (unsigned int j1 = 0; j1 < q - 1; ++j1)
849  for (unsigned int j2 = 0; j2 < q - 1; ++j2)
850  if ((std::fabs(
851  this->unit_support_points[index_map_inverse[i1 + 1]][0] -
852  fe_q_other
853  ->unit_support_points[index_map_inverse_other[j1 + 1]]
854  [0]) < 1e-14) &&
855  (std::fabs(
856  this->unit_support_points[index_map_inverse[i2 + 1]][0] -
857  fe_q_other
858  ->unit_support_points[index_map_inverse_other[j2 + 1]]
859  [0]) < 1e-14))
860  identities.emplace_back(i1 * (p - 1) + i2, j1 * (q - 1) + j2);
861 
862  return identities;
863  }
864  else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
865  {
866  // the FE_Nothing has no degrees of freedom, so there are no
867  // equivalencies to be recorded
868  return std::vector<std::pair<unsigned int, unsigned int>>();
869  }
870  else if (fe_other.dofs_per_face == 0)
871  {
872  // if the other element has no elements on faces at all,
873  // then it would be impossible to enforce any kind of
874  // continuity even if we knew exactly what kind of element
875  // we have -- simply because the other element declares
876  // that it is discontinuous because it has no DoFs on
877  // its faces. in that case, just state that we have no
878  // constraints to declare
879  return std::vector<std::pair<unsigned int, unsigned int>>();
880  }
881  else
882  {
883  Assert(false, ExcNotImplemented());
884  return std::vector<std::pair<unsigned int, unsigned int>>();
885  }
886 }
887 
888 
889 
890 template <class PolynomialType, int dim, int spacedim>
893  const FiniteElement<dim, spacedim> &fe_other) const
894 {
895  if (const FE_Q_Base<PolynomialType, dim, spacedim> *fe_q_other =
896  dynamic_cast<const FE_Q_Base<PolynomialType, dim, spacedim> *>(
897  &fe_other))
898  {
899  if (this->degree < fe_q_other->degree)
901  else if (this->degree == fe_q_other->degree)
903  else
905  }
906  else if (const FE_Nothing<dim, spacedim> *fe_nothing =
907  dynamic_cast<const FE_Nothing<dim, spacedim> *>(&fe_other))
908  {
909  if (fe_nothing->is_dominating())
910  {
912  }
913  else
914  {
915  // the FE_Nothing has no degrees of freedom and it is typically used
916  // in a context where we don't require any continuity along the
917  // interface
919  }
920  }
921  else if ((dynamic_cast<const FE_DGQ<dim, spacedim> *>(&fe_other) !=
922  nullptr) ||
923  (dynamic_cast<const FE_DGP<dim, spacedim> *>(&fe_other) != nullptr))
924  {
925  // there are no requirements between continuous and
926  // discontinuous elements
928  }
929 
930  Assert(false, ExcNotImplemented());
932 }
933 
934 
935 //---------------------------------------------------------------------------
936 // Auxiliary functions
937 //---------------------------------------------------------------------------
938 
939 
940 
941 template <class PolynomialType, int dim, int spacedim>
942 void
944  const std::vector<Point<1>> &points)
945 {
946  const std::vector<unsigned int> &index_map_inverse =
947  this->poly_space.get_numbering_inverse();
948 
949  // We can compute the support points by computing the tensor
950  // product of the 1d set of points. We could do this by hand, but it's
951  // easier to just re-use functionality that's already been implemented
952  // for quadrature formulas.
953  const Quadrature<1> support_1d(points);
954  const Quadrature<dim> support_quadrature(support_1d); // NOLINT
955 
956  // The only thing we have to do is reorder the points from tensor
957  // product order to the order in which we enumerate DoFs on cells
958  this->unit_support_points.resize(support_quadrature.size());
959  for (unsigned int k = 0; k < support_quadrature.size(); ++k)
960  this->unit_support_points[index_map_inverse[k]] =
961  support_quadrature.point(k);
962 }
963 
964 
965 
966 template <class PolynomialType, int dim, int spacedim>
967 void
969  const std::vector<Point<1>> &points)
970 {
971  // no faces in 1d, so nothing to do
972  if (dim == 1)
973  return;
974 
975  this->unit_face_support_points.resize(
976  Utilities::fixed_power<dim - 1>(q_degree + 1));
977 
978  // find renumbering of faces and assign from values of quadrature
979  const std::vector<unsigned int> face_index_map =
980  internal::FE_Q_Base::face_lexicographic_to_hierarchic_numbering<dim>(
981  q_degree);
982 
983  // We can compute the support points by computing the tensor
984  // product of the 1d set of points. We could do this by hand, but it's
985  // easier to just re-use functionality that's already been implemented
986  // for quadrature formulas.
987  const Quadrature<1> support_1d(points);
988  const Quadrature<dim - 1> support_quadrature(support_1d); // NOLINT
989 
990  // The only thing we have to do is reorder the points from tensor
991  // product order to the order in which we enumerate DoFs on cells
992  this->unit_face_support_points.resize(support_quadrature.size());
993  for (unsigned int k = 0; k < support_quadrature.size(); ++k)
994  this->unit_face_support_points[face_index_map[k]] =
995  support_quadrature.point(k);
996 }
997 
998 
999 
1000 template <class PolynomialType, int dim, int spacedim>
1001 void
1004 {
1005  // for 1D and 2D, do nothing
1006  if (dim < 3)
1007  return;
1008 
1010  8 * this->dofs_per_quad,
1011  ExcInternalError());
1012 
1013  const unsigned int n = q_degree - 1;
1014  Assert(n * n == this->dofs_per_quad, ExcInternalError());
1015 
1016  // the dofs on a face are connected to a n x n matrix. for example, for
1017  // degree==4 we have the following dofs on a quad
1018 
1019  // ___________
1020  // | |
1021  // | 6 7 8 |
1022  // | |
1023  // | 3 4 5 |
1024  // | |
1025  // | 0 1 2 |
1026  // |___________|
1027  //
1028  // we have dof_no=i+n*j with index i in x-direction and index j in
1029  // y-direction running from 0 to n-1. to extract i and j we can use
1030  // i=dof_no%n and j=dof_no/n. i and j can then be used to construct the
1031  // rotated and mirrored numbers.
1032 
1033 
1034  for (unsigned int local = 0; local < this->dofs_per_quad; ++local)
1035  // face support points are in lexicographic ordering with x running
1036  // fastest. invert that (y running fastest)
1037  {
1038  unsigned int i = local % n, j = local / n;
1039 
1040  // face_orientation=false, face_flip=false, face_rotation=false
1042  j + i * n - local;
1043  // face_orientation=false, face_flip=false, face_rotation=true
1045  i + (n - 1 - j) * n - local;
1046  // face_orientation=false, face_flip=true, face_rotation=false
1048  (n - 1 - j) + (n - 1 - i) * n - local;
1049  // face_orientation=false, face_flip=true, face_rotation=true
1051  (n - 1 - i) + j * n - local;
1052  // face_orientation=true, face_flip=false, face_rotation=false
1054  // face_orientation=true, face_flip=false, face_rotation=true
1056  j + (n - 1 - i) * n - local;
1057  // face_orientation=true, face_flip=true, face_rotation=false
1059  (n - 1 - i) + (n - 1 - j) * n - local;
1060  // face_orientation=true, face_flip=true, face_rotation=true
1062  (n - 1 - j) + i * n - local;
1063  }
1064 
1065  // additionally initialize reordering of line dofs
1066  for (unsigned int i = 0; i < this->dofs_per_line; ++i)
1068  this->dofs_per_line - 1 - i - i;
1069 }
1070 
1071 
1072 
1073 template <class PolynomialType, int dim, int spacedim>
1074 unsigned int
1076  const unsigned int face_index,
1077  const unsigned int face,
1078  const bool face_orientation,
1079  const bool face_flip,
1080  const bool face_rotation) const
1081 {
1082  Assert(face_index < this->dofs_per_face,
1083  ExcIndexRange(face_index, 0, this->dofs_per_face));
1086 
1087  // TODO: we could presumably solve the 3d case below using the
1088  // adjust_quad_dof_index_for_face_orientation_table field. for the
1089  // 2d case, we can't use adjust_line_dof_index_for_line_orientation_table
1090  // since that array is empty (presumably because we thought that
1091  // there are no flipped edges in 2d, but these can happen in
1092  // DoFTools::make_periodicity_constraints, for example). so we
1093  // would need to either fill this field, or rely on derived classes
1094  // implementing this function, as we currently do
1095 
1096  // we need to distinguish between DoFs on vertices, lines and in 3d quads.
1097  // do so in a sequence of if-else statements
1098  if (face_index < this->first_face_line_index)
1099  // DoF is on a vertex
1100  {
1101  // get the number of the vertex on the face that corresponds to this DoF,
1102  // along with the number of the DoF on this vertex
1103  const unsigned int face_vertex = face_index / this->dofs_per_vertex;
1104  const unsigned int dof_index_on_vertex =
1105  face_index % this->dofs_per_vertex;
1106 
1107  // then get the number of this vertex on the cell and translate
1108  // this to a DoF number on the cell
1110  face, face_vertex, face_orientation, face_flip, face_rotation) *
1111  this->dofs_per_vertex +
1112  dof_index_on_vertex);
1113  }
1114  else if (face_index < this->first_face_quad_index)
1115  // DoF is on a face
1116  {
1117  // do the same kind of translation as before. we need to only consider
1118  // DoFs on the lines, i.e., ignoring those on the vertices
1119  const unsigned int index = face_index - this->first_face_line_index;
1120 
1121  const unsigned int face_line = index / this->dofs_per_line;
1122  const unsigned int dof_index_on_line = index % this->dofs_per_line;
1123 
1124  // we now also need to adjust the line index for the case of
1125  // face orientation, face flips, etc
1126  unsigned int adjusted_dof_index_on_line = 0;
1127  switch (dim)
1128  {
1129  case 1:
1130  Assert(false, ExcInternalError());
1131  break;
1132 
1133  case 2:
1134  // in 2d, only face_flip has a meaning. if it is set, consider
1135  // dofs in reverse order
1136  if (face_flip == false)
1137  adjusted_dof_index_on_line = dof_index_on_line;
1138  else
1139  adjusted_dof_index_on_line =
1140  this->dofs_per_line - dof_index_on_line - 1;
1141  break;
1142 
1143  case 3:
1144  // in 3d, things are difficult. someone will have to think
1145  // about how this code here should look like, by drawing a bunch
1146  // of pictures of how all the faces can look like with the various
1147  // flips and rotations.
1148  //
1149  // that said, the Q2 case is easy enough to implement, as is the
1150  // case where everything is in standard orientation
1151  Assert((this->dofs_per_line <= 1) ||
1152  ((face_orientation == true) && (face_flip == false) &&
1153  (face_rotation == false)),
1154  ExcNotImplemented());
1155  adjusted_dof_index_on_line = dof_index_on_line;
1156  break;
1157 
1158  default:
1159  Assert(false, ExcInternalError());
1160  }
1161 
1162  return (this->first_line_index +
1164  face, face_line, face_orientation, face_flip, face_rotation) *
1165  this->dofs_per_line +
1166  adjusted_dof_index_on_line);
1167  }
1168  else
1169  // DoF is on a quad
1170  {
1171  Assert(dim >= 3, ExcInternalError());
1172 
1173  // ignore vertex and line dofs
1174  const unsigned int index = face_index - this->first_face_quad_index;
1175 
1176  // the same is true here as above for the 3d case -- someone will
1177  // just have to draw a bunch of pictures. in the meantime,
1178  // we can implement the Q2 case in which it is simple
1179  Assert((this->dofs_per_quad <= 1) ||
1180  ((face_orientation == true) && (face_flip == false) &&
1181  (face_rotation == false)),
1182  ExcNotImplemented());
1183  return (this->first_quad_index + face * this->dofs_per_quad + index);
1184  }
1185 }
1186 
1187 
1188 
1189 template <class PolynomialType, int dim, int spacedim>
1190 std::vector<unsigned int>
1192  const unsigned int degree)
1193 {
1195  AssertThrow(degree > 0, typename FEQ::ExcFEQCannotHaveDegree0());
1196  std::vector<unsigned int> dpo(dim + 1, 1U);
1197  for (unsigned int i = 1; i < dpo.size(); ++i)
1198  dpo[i] = dpo[i - 1] * (degree - 1);
1199  return dpo;
1200 }
1201 
1202 
1203 
1204 template <class PolynomialType, int dim, int spacedim>
1205 void
1207  const std::vector<Point<1>> &points)
1208 {
1210 }
1211 
1212 
1213 
1214 template <class PolynomialType, int dim, int spacedim>
1215 const FullMatrix<double> &
1217  const unsigned int child,
1218  const RefinementCase<dim> &refinement_case) const
1219 {
1220  Assert(refinement_case < RefinementCase<dim>::isotropic_refinement + 1,
1221  ExcIndexRange(refinement_case,
1222  0,
1224  Assert(refinement_case != RefinementCase<dim>::no_refinement,
1225  ExcMessage(
1226  "Prolongation matrices are only available for refined cells!"));
1227  Assert(child < GeometryInfo<dim>::n_children(refinement_case),
1228  ExcIndexRange(child,
1229  0,
1230  GeometryInfo<dim>::n_children(refinement_case)));
1231 
1232  // initialization upon first request
1233  if (this->prolongation[refinement_case - 1][child].n() == 0)
1234  {
1235  Threads::Mutex::ScopedLock lock(this->mutex);
1236 
1237  // if matrix got updated while waiting for the lock
1238  if (this->prolongation[refinement_case - 1][child].n() ==
1239  this->dofs_per_cell)
1240  return this->prolongation[refinement_case - 1][child];
1241 
1242  // distinguish q/q_dg0 case: only treat Q dofs first
1243  const unsigned int q_dofs_per_cell =
1244  Utilities::fixed_power<dim>(q_degree + 1);
1245 
1246  // compute the interpolation matrices in much the same way as we do for
1247  // the constraints. it's actually simpler here, since we don't have this
1248  // weird renumbering stuff going on. The trick is again that we the
1249  // interpolation matrix is formed by a permutation of the indices of the
1250  // cell matrix. The value eps is used a threshold to decide when certain
1251  // evaluations of the Lagrange polynomials are zero or one.
1252  const double eps = 1e-15 * q_degree * dim;
1253 
1254 #ifdef DEBUG
1255  // in DEBUG mode, check that the evaluation of support points in the
1256  // current numbering gives the identity operation
1257  for (unsigned int i = 0; i < q_dofs_per_cell; ++i)
1258  {
1259  Assert(std::fabs(1. - this->poly_space.compute_value(
1260  i, this->unit_support_points[i])) < eps,
1261  ExcInternalError("The Lagrange polynomial does not evaluate "
1262  "to one or zero in a nodal point. "
1263  "This typically indicates that the "
1264  "polynomial interpolation is "
1265  "ill-conditioned such that round-off "
1266  "prevents the sum to be one."));
1267  for (unsigned int j = 0; j < q_dofs_per_cell; ++j)
1268  if (j != i)
1269  Assert(std::fabs(this->poly_space.compute_value(
1270  i, this->unit_support_points[j])) < eps,
1272  "The Lagrange polynomial does not evaluate "
1273  "to one or zero in a nodal point. "
1274  "This typically indicates that the "
1275  "polynomial interpolation is "
1276  "ill-conditioned such that round-off "
1277  "prevents the sum to be one."));
1278  }
1279 #endif
1280 
1281  // to efficiently evaluate the polynomial at the subcell, make use of
1282  // the tensor product structure of this element and only evaluate 1D
1283  // information from the polynomial. This makes the cost of this function
1284  // almost negligible also for high order elements
1285  const unsigned int dofs1d = q_degree + 1;
1286  std::vector<Table<2, double>> subcell_evaluations(
1287  dim, Table<2, double>(dofs1d, dofs1d));
1288  const std::vector<unsigned int> &index_map_inverse =
1289  this->poly_space.get_numbering_inverse();
1290 
1291  // helper value: step size how to walk through diagonal and how many
1292  // points we have left apart from the first dimension
1293  unsigned int step_size_diag = 0;
1294  {
1295  unsigned int factor = 1;
1296  for (unsigned int d = 0; d < dim; ++d)
1297  {
1298  step_size_diag += factor;
1299  factor *= dofs1d;
1300  }
1301  }
1302 
1303  FullMatrix<double> prolongate(this->dofs_per_cell, this->dofs_per_cell);
1304 
1305  // go through the points in diagonal to capture variation in all
1306  // directions simultaneously
1307  for (unsigned int j = 0; j < dofs1d; ++j)
1308  {
1309  const unsigned int diag_comp = index_map_inverse[j * step_size_diag];
1310  const Point<dim> p_subcell = this->unit_support_points[diag_comp];
1311  const Point<dim> p_cell =
1313  child,
1314  refinement_case);
1315  for (unsigned int i = 0; i < dofs1d; ++i)
1316  for (unsigned int d = 0; d < dim; ++d)
1317  {
1318  // evaluate along line where only x is different from zero
1319  Point<dim> point;
1320  point[0] = p_cell[d];
1321  const double cell_value =
1322  this->poly_space.compute_value(index_map_inverse[i], point);
1323 
1324  // cut off values that are too small. note that we have here
1325  // Lagrange interpolation functions, so they should be zero at
1326  // almost all points, and one at the others, at least on the
1327  // subcells. so set them to their exact values
1328  //
1329  // the actual cut-off value is somewhat fuzzy, but it works
1330  // for 2e-13*degree*dim (see above), which is kind of
1331  // reasonable given that we compute the values of the
1332  // polynomials via an degree-step recursion and then multiply
1333  // the 1d-values. this gives us a linear growth in degree*dim,
1334  // times a small constant.
1335  //
1336  // the embedding matrix is given by applying the inverse of
1337  // the subcell matrix on the cell_interpolation matrix. since
1338  // the subcell matrix is actually only a permutation vector,
1339  // all we need to do is to switch the rows we write the data
1340  // into. moreover, cut off very small values here
1341  if (std::fabs(cell_value) < eps)
1342  subcell_evaluations[d](j, i) = 0;
1343  else
1344  subcell_evaluations[d](j, i) = cell_value;
1345  }
1346  }
1347 
1348  // now expand from 1D info. block innermost dimension (x_0) in order to
1349  // avoid difficult checks at innermost loop
1350  unsigned int j_indices[dim];
1351  internal::FE_Q_Base::zero_indices<dim>(j_indices);
1352  for (unsigned int j = 0; j < q_dofs_per_cell; j += dofs1d)
1353  {
1354  unsigned int i_indices[dim];
1355  internal::FE_Q_Base::zero_indices<dim>(i_indices);
1356  for (unsigned int i = 0; i < q_dofs_per_cell; i += dofs1d)
1357  {
1358  double val_extra_dim = 1.;
1359  for (unsigned int d = 1; d < dim; ++d)
1360  val_extra_dim *=
1361  subcell_evaluations[d](j_indices[d - 1], i_indices[d - 1]);
1362 
1363  // innermost sum where we actually compute. the same as
1364  // prolongate(j,i) = this->poly_space.compute_value (i, p_cell)
1365  for (unsigned int jj = 0; jj < dofs1d; ++jj)
1366  {
1367  const unsigned int j_ind = index_map_inverse[j + jj];
1368  for (unsigned int ii = 0; ii < dofs1d; ++ii)
1369  prolongate(j_ind, index_map_inverse[i + ii]) =
1370  val_extra_dim * subcell_evaluations[0](jj, ii);
1371  }
1372 
1373  // update indices that denote the tensor product position. a bit
1374  // fuzzy and therefore not done for innermost x_0 direction
1375  internal::FE_Q_Base::increment_indices<dim>(i_indices, dofs1d);
1376  }
1377  Assert(i_indices[dim - 1] == 1, ExcInternalError());
1378  internal::FE_Q_Base::increment_indices<dim>(j_indices, dofs1d);
1379  }
1380 
1381  // the discontinuous node is simply mapped on the discontinuous node on
1382  // the child element
1383  if (q_dofs_per_cell < this->dofs_per_cell)
1384  prolongate(q_dofs_per_cell, q_dofs_per_cell) = 1.;
1385 
1386  // and make sure that the row sum is 1. this must be so since for this
1387  // element, the shape functions add up to one
1388 #ifdef DEBUG
1389  for (unsigned int row = 0; row < this->dofs_per_cell; ++row)
1390  {
1391  double sum = 0;
1392  for (unsigned int col = 0; col < this->dofs_per_cell; ++col)
1393  sum += prolongate(row, col);
1394  Assert(std::fabs(sum - 1.) <
1395  std::max(eps, 5e-16 * std::sqrt(this->dofs_per_cell)),
1396  ExcInternalError("The entries in a row of the local "
1397  "prolongation matrix do not add to one. "
1398  "This typically indicates that the "
1399  "polynomial interpolation is "
1400  "ill-conditioned such that round-off "
1401  "prevents the sum to be one."));
1402  }
1403 #endif
1404 
1405  // swap matrices
1406  prolongate.swap(const_cast<FullMatrix<double> &>(
1407  this->prolongation[refinement_case - 1][child]));
1408  }
1409 
1410  // finally return the matrix
1411  return this->prolongation[refinement_case - 1][child];
1412 }
1413 
1414 
1415 
1416 template <class PolynomialType, int dim, int spacedim>
1417 const FullMatrix<double> &
1419  const unsigned int child,
1420  const RefinementCase<dim> &refinement_case) const
1421 {
1422  Assert(refinement_case < RefinementCase<dim>::isotropic_refinement + 1,
1423  ExcIndexRange(refinement_case,
1424  0,
1426  Assert(refinement_case != RefinementCase<dim>::no_refinement,
1427  ExcMessage(
1428  "Restriction matrices are only available for refined cells!"));
1429  Assert(child < GeometryInfo<dim>::n_children(refinement_case),
1430  ExcIndexRange(child,
1431  0,
1432  GeometryInfo<dim>::n_children(refinement_case)));
1433 
1434  // initialization upon first request
1435  if (this->restriction[refinement_case - 1][child].n() == 0)
1436  {
1437  Threads::Mutex::ScopedLock lock(this->mutex);
1438 
1439  // if matrix got updated while waiting for the lock...
1440  if (this->restriction[refinement_case - 1][child].n() ==
1441  this->dofs_per_cell)
1442  return this->restriction[refinement_case - 1][child];
1443 
1444  FullMatrix<double> my_restriction(this->dofs_per_cell,
1445  this->dofs_per_cell);
1446  // distinguish q/q_dg0 case
1447  const unsigned int q_dofs_per_cell =
1448  Utilities::fixed_power<dim>(q_degree + 1);
1449 
1450  // for Lagrange interpolation polynomials based on equidistant points,
1451  // construction of the restriction matrices is relatively simple. the
1452  // reason is that in this case the interpolation points on the mother
1453  // cell are always also interpolation points for some shape function on
1454  // one or the other child.
1455  //
1456  // in the general case with non-equidistant points, we need to actually
1457  // do an interpolation. thus, we take the interpolation points on the
1458  // mother cell and evaluate the shape functions of the child cell on
1459  // those points. it does not hurt in the equidistant case because then
1460  // simple one shape function evaluates to one and the others to zero.
1461  //
1462  // this element is non-additive in all its degrees of freedom by
1463  // default, which requires care in downstream use. fortunately, even the
1464  // interpolation on non-equidistant points is invariant under the
1465  // assumption that whenever a row makes a non-zero contribution to the
1466  // mother's residual, the correct value is interpolated.
1467 
1468  const double eps = 1e-15 * q_degree * dim;
1469  const std::vector<unsigned int> &index_map_inverse =
1470  this->poly_space.get_numbering_inverse();
1471 
1472  const unsigned int dofs1d = q_degree + 1;
1473  std::vector<Tensor<1, dim>> evaluations1d(dofs1d);
1474 
1475  my_restriction.reinit(this->dofs_per_cell, this->dofs_per_cell);
1476 
1477  for (unsigned int i = 0; i < q_dofs_per_cell; ++i)
1478  {
1479  unsigned int mother_dof = index_map_inverse[i];
1480  const Point<dim> p_cell = this->unit_support_points[mother_dof];
1481 
1482  // check whether this interpolation point is inside this child cell
1483  const Point<dim> p_subcell =
1485  child,
1486  refinement_case);
1488  {
1489  // same logic as in initialize_embedding to evaluate the
1490  // polynomial faster than from the tensor product: since we
1491  // evaluate all polynomials, it is much faster to just compute
1492  // the 1D values for all polynomials before and then get the
1493  // dim-data.
1494  for (unsigned int j = 0; j < dofs1d; ++j)
1495  for (unsigned int d = 0; d < dim; ++d)
1496  {
1497  Point<dim> point;
1498  point[0] = p_subcell[d];
1499  evaluations1d[j][d] =
1500  this->poly_space.compute_value(index_map_inverse[j],
1501  point);
1502  }
1503  unsigned int j_indices[dim];
1504  internal::FE_Q_Base::zero_indices<dim>(j_indices);
1505  double sum_check = 0;
1506  for (unsigned int j = 0; j < q_dofs_per_cell; j += dofs1d)
1507  {
1508  double val_extra_dim = 1.;
1509  for (unsigned int d = 1; d < dim; ++d)
1510  val_extra_dim *= evaluations1d[j_indices[d - 1]][d];
1511  for (unsigned int jj = 0; jj < dofs1d; ++jj)
1512  {
1513  // find the child shape function(s) corresponding to
1514  // this point. Usually this is just one function;
1515  // however, when we use FE_Q on arbitrary nodes a parent
1516  // support point might not be a child support point, and
1517  // then we will get more than one nonzero value per
1518  // row. Still, the values should sum up to 1
1519  const double val = val_extra_dim * evaluations1d[jj][0];
1520  const unsigned int child_dof = index_map_inverse[j + jj];
1521  if (std::fabs(val - 1.) < eps)
1522  my_restriction(mother_dof, child_dof) = 1.;
1523  else if (std::fabs(val) > eps)
1524  my_restriction(mother_dof, child_dof) = val;
1525  sum_check += val;
1526  }
1527  internal::FE_Q_Base::increment_indices<dim>(j_indices,
1528  dofs1d);
1529  }
1530  Assert(std::fabs(sum_check - 1) <
1531  std::max(eps, 5e-16 * std::sqrt(this->dofs_per_cell)),
1532  ExcInternalError("The entries in a row of the local "
1533  "restriction matrix do not add to one. "
1534  "This typically indicates that the "
1535  "polynomial interpolation is "
1536  "ill-conditioned such that round-off "
1537  "prevents the sum to be one."));
1538  }
1539 
1540  // part for FE_Q_DG0
1541  if (q_dofs_per_cell < this->dofs_per_cell)
1542  my_restriction(this->dofs_per_cell - 1, this->dofs_per_cell - 1) =
1544  RefinementCase<dim>(refinement_case));
1545  }
1546 
1547  // swap the just computed restriction matrix into the
1548  // element of the vector stored in the base class
1549  my_restriction.swap(const_cast<FullMatrix<double> &>(
1550  this->restriction[refinement_case - 1][child]));
1551  }
1552 
1553  return this->restriction[refinement_case - 1][child];
1554 }
1555 
1556 
1557 
1558 //---------------------------------------------------------------------------
1559 // Data field initialization
1560 //---------------------------------------------------------------------------
1561 
1562 
1563 template <class PolynomialType, int dim, int spacedim>
1564 bool
1566  const unsigned int shape_index,
1567  const unsigned int face_index) const
1568 {
1569  Assert(shape_index < this->dofs_per_cell,
1570  ExcIndexRange(shape_index, 0, this->dofs_per_cell));
1573 
1574  // in 1d, things are simple. since there is only one degree of freedom per
1575  // vertex in this class, the first is on vertex 0 (==face 0 in some sense),
1576  // the second on face 1:
1577  if (dim == 1)
1578  return (((shape_index == 0) && (face_index == 0)) ||
1579  ((shape_index == 1) && (face_index == 1)));
1580 
1581  // first, special-case interior shape functions, since they have no support
1582  // no-where on the boundary
1583  if (((dim == 2) && (shape_index >= this->first_quad_index)) ||
1584  ((dim == 3) && (shape_index >= this->first_hex_index)))
1585  return false;
1586 
1587  // let's see whether this is a vertex
1588  if (shape_index < this->first_line_index)
1589  {
1590  // for Q elements, there is one dof per vertex, so
1591  // shape_index==vertex_number. check whether this vertex is on the given
1592  // face. thus, for each face, give a list of vertices
1593  const unsigned int vertex_no = shape_index;
1595  ExcInternalError());
1596 
1597  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_face; ++v)
1598  if (GeometryInfo<dim>::face_to_cell_vertices(face_index, v) ==
1599  vertex_no)
1600  return true;
1601 
1602  return false;
1603  }
1604  else if (shape_index < this->first_quad_index)
1605  // ok, dof is on a line
1606  {
1607  const unsigned int line_index =
1608  (shape_index - this->first_line_index) / this->dofs_per_line;
1610  ExcInternalError());
1611 
1612  // in 2d, the line is the face, so get the line index
1613  if (dim == 2)
1614  return (line_index == face_index);
1615  else if (dim == 3)
1616  {
1617  // silence compiler warning
1618  const unsigned int lines_per_face =
1619  dim == 3 ? GeometryInfo<dim>::lines_per_face : 1;
1620  // see whether the given line is on the given face.
1621  for (unsigned int l = 0; l < lines_per_face; ++l)
1622  if (GeometryInfo<3>::face_to_cell_lines(face_index, l) ==
1623  line_index)
1624  return true;
1625 
1626  return false;
1627  }
1628  else
1629  Assert(false, ExcNotImplemented());
1630  }
1631  else if (shape_index < this->first_hex_index)
1632  // dof is on a quad
1633  {
1634  const unsigned int quad_index =
1635  (shape_index - this->first_quad_index) / this->dofs_per_quad;
1636  Assert(static_cast<signed int>(quad_index) <
1637  static_cast<signed int>(GeometryInfo<dim>::quads_per_cell),
1638  ExcInternalError());
1639 
1640  // in 2d, cell bubble are zero on all faces. but we have treated this
1641  // case above already
1642  Assert(dim != 2, ExcInternalError());
1643 
1644  // in 3d, quad_index=face_index
1645  if (dim == 3)
1646  return (quad_index == face_index);
1647  else
1648  Assert(false, ExcNotImplemented());
1649  }
1650  else
1651  // dof on hex
1652  {
1653  // can only happen in 3d, but this case has already been covered above
1654  Assert(false, ExcNotImplemented());
1655  return false;
1656  }
1657 
1658  // we should not have gotten here
1659  Assert(false, ExcInternalError());
1660  return false;
1661 }
1662 
1663 
1664 
1665 template <typename PolynomialType, int dim, int spacedim>
1666 std::pair<Table<2, bool>, std::vector<unsigned int>>
1668 {
1669  Table<2, bool> constant_modes(1, this->dofs_per_cell);
1670  // We here just care for the constant mode due to the polynomial space
1671  // without any enrichments
1672  // As there may be more constant modes derived classes may to implement this
1673  // themselves. An example for this is FE_Q_DG0.
1674  for (unsigned int i = 0; i < Utilities::fixed_power<dim>(q_degree + 1); ++i)
1675  constant_modes(0, i) = true;
1676  return std::pair<Table<2, bool>, std::vector<unsigned int>>(
1677  constant_modes, std::vector<unsigned int>(1, 0));
1678 }
1679 
1680 
1681 
1682 // explicit instantiations
1683 #include "fe_q_base.inst"
1684 
1685 DEAL_II_NAMESPACE_CLOSE
static Point< dim > child_to_cell_coordinates(const Point< dim > &p, const unsigned int child_index, const RefinementCase< dim > refine_case=RefinementCase< dim >::isotropic_refinement)
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_q_base.cc:757
const unsigned int first_hex_index
Definition: fe_base.h:273
FE_Q_Base(const PolynomialType &poly_space, const FiniteElementData< dim > &fe_data, const std::vector< bool > &restriction_is_additive_flags)
Definition: fe_q_base.cc:433
static const unsigned int invalid_unsigned_int
Definition: types.h:173
std::vector< std::vector< FullMatrix< double > > > restriction
Definition: fe.h:2419
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1366
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const override
Definition: fe_q_base.cc:597
void swap(TableBase< N, T > &v)
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
Definition: fe_q_base.cc:1191
static void initialize_constraints(const std::vector< Point< 1 >> &, FE_Q_Base< PolynomialType, 1, spacedim > &)
Definition: fe_q_base.cc:117
FullMatrix< double > interface_constraints
Definition: fe.h:2445
virtual double shape_value(const unsigned int i, const Point< dim > &p) const override
Task< RT > new_task(const std::function< RT()> &function)
Definition: fe_dgq.h:109
const unsigned int dofs_per_quad
Definition: fe_base.h:252
void hierarchic_to_lexicographic_numbering(unsigned int degree, std::vector< unsigned int > &h2l)
const unsigned int degree
Definition: fe_base.h:313
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const override
Definition: fe_q_base.cc:1565
static Point< dim > cell_to_child_coordinates(const Point< dim > &p, const unsigned int child_index, const RefinementCase< dim > refine_case=RefinementCase< dim >::isotropic_refinement)
std::vector< Point< dim-1 > > unit_face_support_points
Definition: fe.h:2464
STL namespace.
TableIndices< 2 > interface_constraints_size() const
Definition: fe.cc:857
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
static::ExceptionBase & ExcInterpolationNotImplemented()
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
Definition: fe_q_base.cc:1216
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
const unsigned int dofs_per_line
Definition: fe_base.h:246
Definition: point.h:106
const Point< dim > & point(const unsigned int i) const
std::vector< Point< dim > > unit_support_points
Definition: fe.h:2457
const unsigned int first_face_line_index
Definition: fe_base.h:278
Definition: fe_dgp.h:311
unsigned int size() const
void initialize_unit_face_support_points(const std::vector< Point< 1 >> &points)
Definition: fe_q_base.cc:968
static::ExceptionBase & ExcMessage(std::string arg1)
size_type n() const
static::ExceptionBase & ExcImpossibleInDim(int arg1)
const unsigned int first_quad_index
Definition: fe_base.h:268
std::vector< std::vector< FullMatrix< double > > > prolongation
Definition: fe.h:2433
void reinit(const TableIndices< N > &new_size, const bool omit_default_initialization=false)
#define Assert(cond, exc)
Definition: exceptions.h:1227
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
virtual FiniteElementDomination::Domination compare_for_face_domination(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_q_base.cc:892
void initialize_unit_support_points(const std::vector< Point< 1 >> &points)
Definition: fe_q_base.cc:943
virtual void get_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const override
Definition: fe_q_base.cc:499
virtual const FullMatrix< double > & get_restriction_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
Definition: fe_q_base.cc:1418
size_type m() const
virtual unsigned int face_to_cell_index(const unsigned int face_dof_index, const unsigned int face, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false) const override
Definition: fe_q_base.cc:1075
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix) const override
Definition: fe_q_base.cc:611
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_quad_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_q_base.cc:822
void initialize_constraints(const std::vector< Point< 1 >> &points)
Definition: fe_q_base.cc:1206
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
const unsigned int dofs_per_cell
Definition: fe_base.h:297
void lexicographic_to_hierarchic_numbering(const FiniteElementData< dim > &fe_data, std::vector< unsigned int > &l2h)
virtual bool hp_constraints_are_implemented() const override
Definition: fe_q_base.cc:707
static unsigned int n_children(const RefinementCase< dim > &refinement_case)
void initialize(const std::vector< Point< 1 >> &support_points_1d)
Definition: fe_q_base.cc:452
static void project_to_subface(const SubQuadrature &quadrature, const unsigned int face_no, const unsigned int subface_no, std::vector< Point< dim >> &q_points, const RefinementCase< dim-1 > &ref_case=RefinementCase< dim-1 >::isotropic_refinement)
size_type n_elements() const
static void project_to_face(const SubQuadrature &quadrature, const unsigned int face_no, std::vector< Point< dim >> &q_points)
Table< 2, int > adjust_quad_dof_index_for_face_orientation_table
Definition: fe.h:2493
void initialize_quad_dof_index_permutation()
Definition: fe_q_base.cc:1003
const unsigned int first_face_quad_index
Definition: fe_base.h:283
const unsigned int dofs_per_face
Definition: fe_base.h:290
const unsigned int first_line_index
Definition: fe_base.h:263
static::ExceptionBase & ExcNotImplemented()
const unsigned int dofs_per_vertex
Definition: fe_base.h:240
PolynomialType poly_space
Definition: fe_poly.h:480
std::vector< int > adjust_line_dof_index_for_line_orientation_table
Definition: fe.h:2508
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_q_base.cc:716
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const override
Definition: fe_q_base.cc:1667
static::ExceptionBase & ExcInternalError()