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