Reference documentation for deal.II version 9.0.0
fe_face.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2009 - 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/fe/fe_face.h>
18 #include <deal.II/fe/fe_poly_face.templates.h>
19 #include <deal.II/fe/fe_nothing.h>
20 #include <deal.II/fe/fe_tools.h>
21 #include <deal.II/base/quadrature_lib.h>
22 #include <deal.II/lac/householder.h>
23 
24 #include <sstream>
25 #include <deal.II/base/std_cxx14/memory.h>
26 
27 DEAL_II_NAMESPACE_OPEN
28 
29 
30 namespace internal
31 {
32  namespace FE_FaceQImplementation
33  {
34  namespace
35  {
36  std::vector<Point<1> >
37  get_QGaussLobatto_points (const unsigned int degree)
38  {
39  if (degree > 0)
40  return QGaussLobatto<1>(degree+1).get_points();
41  else
42  return std::vector<Point<1> >(1, Point<1>(0.5));
43  }
44  }
45  }
46 }
47 
48 template <int dim, int spacedim>
49 FE_FaceQ<dim,spacedim>::FE_FaceQ (const unsigned int degree)
50  :
51  FE_PolyFace<TensorProductPolynomials<dim-1>, dim, spacedim>
52  (TensorProductPolynomials<dim-1>(Polynomials::generate_complete_Lagrange_basis(internal::FE_FaceQImplementation::get_QGaussLobatto_points(degree))),
53  FiniteElementData<dim>(get_dpo_vector(degree), 1, degree, FiniteElementData<dim>::L2),
54  std::vector<bool>(1,true))
55 {
56  // initialize unit face support points
57  const unsigned int codim = dim-1;
58  this->unit_face_support_points.resize(Utilities::fixed_power<codim>(this->degree+1));
59 
60  if (this->degree == 0)
61  for (unsigned int d=0; d<codim; ++d)
62  this->unit_face_support_points[0][d] = 0.5;
63  else
64  {
65  std::vector<Point<1> > points = internal::FE_FaceQImplementation::get_QGaussLobatto_points(degree);
66 
67  unsigned int k=0;
68  for (unsigned int iz=0; iz <= ((codim>2) ? this->degree : 0) ; ++iz)
69  for (unsigned int iy=0; iy <= ((codim>1) ? this->degree : 0) ; ++iy)
70  for (unsigned int ix=0; ix<=this->degree; ++ix)
71  {
72  Point<codim> p;
73 
74  p(0) = points[ix][0];
75  if (codim>1)
76  p(1) = points[iy][0];
77  if (codim>2)
78  p(2) = points[iz][0];
79 
80  this->unit_face_support_points[k++] = p;
81  }
82  AssertDimension (k, this->unit_face_support_points.size());
83  }
84 
85  // initialize unit support points (this makes it possible to assign initial
86  // values to FE_FaceQ)
88  this->unit_face_support_points.size());
89  const unsigned int n_face_dofs = this->unit_face_support_points.size();
90  for (unsigned int i=0; i<n_face_dofs; ++i)
91  for (unsigned int d=0; d<dim; ++d)
92  {
93  for (unsigned int e=0, c=0; e<dim; ++e)
94  if (d!=e)
95  {
96  // faces in y-direction are oriented differently
97  unsigned int renumber = i;
98  if (dim == 3 && d == 1)
99  renumber = i/(degree+1)+(degree+1)*(i%(degree+1));
100  this->unit_support_points[n_face_dofs*2*d+i][e] =
101  this->unit_face_support_points[renumber][c];
102  this->unit_support_points[n_face_dofs*(2*d+1)+i][e] =
103  this->unit_face_support_points[renumber][c];
104  this->unit_support_points[n_face_dofs*(2*d+1)+i][d] = 1;
105  ++c;
106  }
107  }
108 }
109 
110 
111 
112 template <int dim, int spacedim>
113 std::unique_ptr<FiniteElement<dim,spacedim> >
115 {
116  return std_cxx14::make_unique<FE_FaceQ<dim,spacedim>>(this->degree);
117 }
118 
119 
120 
121 template <int dim, int spacedim>
122 std::string
124 {
125  // note that the FETools::get_fe_by_name function depends on the
126  // particular format of the string this function returns, so they have to be
127  // kept in synch
128  std::ostringstream namebuf;
129  namebuf << "FE_FaceQ<"
130  << Utilities::dim_string(dim,spacedim)
131  << ">(" << this->degree << ")";
132 
133  return namebuf.str();
134 }
135 
136 
137 
138 template <int dim, int spacedim>
139 void
142  FullMatrix<double> &interpolation_matrix) const
143 {
144  get_subface_interpolation_matrix (source_fe, numbers::invalid_unsigned_int,
145  interpolation_matrix);
146 }
147 
148 
149 
150 template <int dim, int spacedim>
151 void
154  const unsigned int subface,
155  FullMatrix<double> &interpolation_matrix) const
156 {
157  // this function is similar to the respective method in FE_Q
158 
159  Assert (interpolation_matrix.n() == this->dofs_per_face,
160  ExcDimensionMismatch (interpolation_matrix.n(),
161  this->dofs_per_face));
162  Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
163  ExcDimensionMismatch (interpolation_matrix.m(),
164  x_source_fe.dofs_per_face));
165 
166  // see if source is a FaceQ element
167  if (const FE_FaceQ<dim,spacedim> *source_fe
168  = dynamic_cast<const FE_FaceQ<dim,spacedim> *>(&x_source_fe))
169  {
170 
171  // Make sure that the element for which the DoFs should be constrained
172  // is the one with the higher polynomial degree. Actually the procedure
173  // will work also if this assertion is not satisfied. But the matrices
174  // produced in that case might lead to problems in the hp procedures,
175  // which use this method.
176  Assert (this->dofs_per_face <= source_fe->dofs_per_face,
177  (typename FiniteElement<dim,spacedim>::
178  ExcInterpolationNotImplemented ()));
179 
180  // generate a quadrature with the unit face support points.
181  const Quadrature<dim-1> face_quadrature (source_fe->get_unit_face_support_points ());
182 
183  // Rule of thumb for FP accuracy, that can be expected for a given
184  // polynomial degree. This value is used to cut off values close to
185  // zero.
186  const double eps = 2e-13*(this->degree+1)*(dim-1);
187 
188  // compute the interpolation matrix by simply taking the value at the
189  // support points.
190  for (unsigned int i=0; i<source_fe->dofs_per_face; ++i)
191  {
192  const Point<dim-1> p =
194  ?
195  face_quadrature.point(i)
196  :
197  GeometryInfo<dim-1>::child_to_cell_coordinates (face_quadrature.point(i),
198  subface);
199 
200  for (unsigned int j=0; j<this->dofs_per_face; ++j)
201  {
202  double matrix_entry = this->poly_space.compute_value (j, p);
203 
204  // Correct the interpolated value. I.e. if it is close to 1 or 0,
205  // make it exactly 1 or 0. Unfortunately, this is required to avoid
206  // problems with higher order elements.
207  if (std::fabs (matrix_entry - 1.0) < eps)
208  matrix_entry = 1.0;
209  if (std::fabs (matrix_entry) < eps)
210  matrix_entry = 0.0;
211 
212  interpolation_matrix(i,j) = matrix_entry;
213  }
214  }
215 
216  // make sure that the row sum of each of the matrices is 1 at this
217  // point. this must be so since the shape functions sum up to 1
218  for (unsigned int j=0; j<source_fe->dofs_per_face; ++j)
219  {
220  double sum = 0.;
221 
222  for (unsigned int i=0; i<this->dofs_per_face; ++i)
223  sum += interpolation_matrix(j,i);
224 
225  Assert (std::fabs(sum-1) < eps, ExcInternalError());
226  }
227  }
228  else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != nullptr)
229  {
230  // nothing to do here, the FE_Nothing has no degrees of freedom anyway
231  }
232  else
233  AssertThrow (false,(typename FiniteElement<dim,spacedim>::
234  ExcInterpolationNotImplemented()));
235 }
236 
237 
238 
239 template <int dim, int spacedim>
240 bool
242  const unsigned int shape_index,
243  const unsigned int face_index) const
244 {
245  return (face_index == (shape_index/this->dofs_per_face));
246 }
247 
248 
249 
250 template <int dim, int spacedim>
251 std::vector<unsigned int>
253 {
254  std::vector<unsigned int> dpo(dim+1, 0U);
255  dpo[dim-1] = deg+1;
256  for (unsigned int i=1; i<dim-1; ++i)
257  dpo[dim-1] *= deg+1;
258  return dpo;
259 }
260 
261 
262 
263 template <int dim, int spacedim>
264 bool
266 {
267  return true;
268 }
269 
270 
271 
272 template <int dim, int spacedim>
273 std::vector<std::pair<unsigned int, unsigned int> >
276 {
277  // this element is always discontinuous at vertices
278  return
279  std::vector<std::pair<unsigned int, unsigned int> > ();
280 }
281 
282 
283 
284 template <int dim, int spacedim>
285 std::vector<std::pair<unsigned int, unsigned int> >
288 {
289  Assert (dim >= 2, ExcInternalError());
290 
291  // this element is continuous only for the highest dimensional bounding object
292  if (dim > 2)
293  return
294  std::vector<std::pair<unsigned int, unsigned int> > ();
295  else
296  {
297  // this is similar to the FE_Q_Base class
298  if (const FE_FaceQ<dim,spacedim> *fe_q_other
299  = dynamic_cast<const FE_FaceQ<dim,spacedim>*>(&fe_other))
300  {
301  // dofs are located along lines, so two dofs are identical if they are
302  // located at identical positions.
303  // Therefore, read the points in unit_support_points for the
304  // first coordinate direction. We take the lexicographic ordering of the
305  // points in the second direction (i.e., y-direction) since we know
306  // that the first p+1 dofs are located at the left (x=0) face.
307  const unsigned int p = this->degree;
308  const unsigned int q = fe_q_other->degree;
309 
310  std::vector<std::pair<unsigned int, unsigned int> > identities;
311 
312  const std::vector<unsigned int> &index_map_inverse=
313  this->poly_space.get_numbering_inverse();
314  const std::vector<unsigned int> &index_map_inverse_other=
315  fe_q_other->poly_space.get_numbering_inverse();
316 
317  for (unsigned int i=0; i<p+1; ++i)
318  for (unsigned int j=0; j<q+1; ++j)
319  if (std::fabs(this->unit_support_points[index_map_inverse[i]][dim-1]-
320  fe_q_other->unit_support_points[index_map_inverse_other[j]][dim-1])
321  < 1e-14)
322  identities.emplace_back (i, j);
323 
324  return identities;
325  }
326  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != nullptr)
327  {
328  // the FE_Nothing has no degrees of freedom, so there are no
329  // equivalencies to be recorded
330  return std::vector<std::pair<unsigned int, unsigned int> > ();
331  }
332  else if (fe_other.dofs_per_face == 0)
333  {
334  // if the other element has no elements on faces at all,
335  // then it would be impossible to enforce any kind of
336  // continuity even if we knew exactly what kind of element
337  // we have -- simply because the other element declares
338  // that it is discontinuous because it has no DoFs on
339  // its faces. in that case, just state that we have no
340  // constraints to declare
341  return std::vector<std::pair<unsigned int, unsigned int> > ();
342  }
343  else
344  {
345  Assert (false, ExcNotImplemented());
346  return std::vector<std::pair<unsigned int, unsigned int> > ();
347  }
348  }
349 }
350 
351 
352 
353 template <int dim, int spacedim>
354 std::vector<std::pair<unsigned int, unsigned int> >
357 {
358  Assert (dim >= 3, ExcInternalError());
359 
360  // this element is continuous only for the highest dimensional bounding object
361  if (dim > 3)
362  return
363  std::vector<std::pair<unsigned int, unsigned int> > ();
364  else
365  {
366  // this is similar to the FE_Q_Base class
367  if (const FE_FaceQ<dim,spacedim> *fe_q_other
368  = dynamic_cast<const FE_FaceQ<dim,spacedim>*>(&fe_other))
369  {
370  // this works exactly like the line case above, except that now we have
371  // to have two indices i1, i2 and j1, j2 to characterize the dofs on the
372  // face of each of the finite elements. since they are ordered
373  // lexicographically along the first line and we have a tensor product,
374  // the rest is rather straightforward
375  const unsigned int p = this->degree;
376  const unsigned int q = fe_q_other->degree;
377 
378  std::vector<std::pair<unsigned int, unsigned int> > identities;
379 
380  const std::vector<unsigned int> &index_map_inverse=
381  this->poly_space.get_numbering_inverse();
382  const std::vector<unsigned int> &index_map_inverse_other=
383  fe_q_other->poly_space.get_numbering_inverse();
384 
385  std::vector<std::pair<unsigned int, unsigned int> > identities_1d;
386 
387  for (unsigned int i=0; i<p+1; ++i)
388  for (unsigned int j=0; j<q+1; ++j)
389  if (std::fabs(this->unit_support_points[index_map_inverse[i]][dim-2]-
390  fe_q_other->unit_support_points[index_map_inverse_other[j]][dim-2])
391  < 1e-14)
392  identities_1d.emplace_back (i, j);
393 
394  for (unsigned int n1=0; n1<identities_1d.size(); ++n1)
395  for (unsigned int n2=0; n2<identities_1d.size(); ++n2)
396  identities.emplace_back (identities_1d[n1].first*(p+1)+identities_1d[n2].first,
397  identities_1d[n1].second*(q+1)+identities_1d[n2].second);
398 
399  return identities;
400  }
401  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != nullptr)
402  {
403  // the FE_Nothing has no degrees of freedom, so there are no
404  // equivalencies to be recorded
405  return std::vector<std::pair<unsigned int, unsigned int> > ();
406  }
407  else if (fe_other.dofs_per_face == 0)
408  {
409  // if the other element has no elements on faces at all,
410  // then it would be impossible to enforce any kind of
411  // continuity even if we knew exactly what kind of element
412  // we have -- simply because the other element declares
413  // that it is discontinuous because it has no DoFs on
414  // its faces. in that case, just state that we have no
415  // constraints to declare
416  return std::vector<std::pair<unsigned int, unsigned int> > ();
417  }
418  else
419  {
420  Assert (false, ExcNotImplemented());
421  return std::vector<std::pair<unsigned int, unsigned int> > ();
422  }
423  }
424 }
425 
426 
427 
428 template <int dim, int spacedim>
432 {
433  if (const FE_FaceQ<dim,spacedim> *fe_q_other
434  = dynamic_cast<const FE_FaceQ<dim,spacedim>*>(&fe_other))
435  {
436  if (this->degree < fe_q_other->degree)
438  else if (this->degree == fe_q_other->degree)
440  else
442  }
443  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
444  {
445  if (fe_nothing->is_dominating())
446  {
448  }
449  else
450  {
451  // the FE_Nothing has no degrees of freedom and it is typically used in
452  // a context where we don't require any continuity along the interface
454  }
455  }
456 
457  Assert (false, ExcNotImplemented());
459 }
460 
461 
462 
463 template <int dim, int spacedim>
464 std::pair<Table<2,bool>, std::vector<unsigned int> >
466 {
467  Table<2,bool> constant_modes(1, this->dofs_per_cell);
468  for (unsigned int i=0; i<this->dofs_per_cell; ++i)
469  constant_modes(0,i) = true;
470  return std::pair<Table<2,bool>, std::vector<unsigned int> >
471  (constant_modes, std::vector<unsigned int>(1, 0));
472 }
473 
474 template <int dim, int spacedim>
475 void
478  std::vector<double> &nodal_values) const
479 {
480  AssertDimension (support_point_values.size(),
481  this->get_unit_support_points().size());
482  AssertDimension (support_point_values.size(),
483  nodal_values.size());
484  AssertDimension (this->dofs_per_cell,
485  nodal_values.size());
486 
487  for (unsigned int i=0; i<this->dofs_per_cell; ++i)
488  {
489  AssertDimension (support_point_values[i].size(), 1);
490 
491  nodal_values[i] = support_point_values[i](0);
492  }
493 }
494 
495 // ----------------------------- FE_FaceQ<1,spacedim> ------------------------
496 
497 template <int spacedim>
498 FE_FaceQ<1,spacedim>::FE_FaceQ (const unsigned int degree)
499  :
500  FiniteElement<1,spacedim> (FiniteElementData<1>(get_dpo_vector(degree), 1, degree, FiniteElementData<1>::L2),
501  std::vector<bool>(1,true),
502  std::vector<ComponentMask> (1, ComponentMask(1,true)))
503 {
504  this->unit_face_support_points.resize(1);
505 
506  // initialize unit support points (this makes it possible to assign initial
507  // values to FE_FaceQ)
509  this->unit_support_points[1] = Point<1>(1.);
510 }
511 
512 
513 
514 template <int spacedim>
515 std::unique_ptr<FiniteElement<1,spacedim>>
517 {
518  return std_cxx14::make_unique<FE_FaceQ<1,spacedim>>(this->degree);
519 }
520 
521 
522 
523 template <int spacedim>
524 std::string
526 {
527  // note that the FETools::get_fe_by_name function depends on the
528  // particular format of the string this function returns, so they have to be
529  // kept in synch
530  std::ostringstream namebuf;
531  namebuf << "FE_FaceQ<"
532  << Utilities::dim_string(1,spacedim)
533  << ">(" << this->degree << ")";
534 
535  return namebuf.str();
536 }
537 
538 
539 
540 template <int spacedim>
541 void
544  FullMatrix<double> &interpolation_matrix) const
545 {
547  interpolation_matrix);
548 }
549 
550 
551 
552 template <int spacedim>
553 void
556  const unsigned int /*subface*/,
557  FullMatrix<double> &interpolation_matrix) const
558 {
559  (void)x_source_fe;
560  Assert (interpolation_matrix.n() == this->dofs_per_face,
561  ExcDimensionMismatch (interpolation_matrix.n(),
562  this->dofs_per_face));
563  Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
564  ExcDimensionMismatch (interpolation_matrix.m(),
565  x_source_fe.dofs_per_face));
566  interpolation_matrix(0,0) = 1.;
567 }
568 
569 
570 
571 template <int spacedim>
572 bool
574  const unsigned int shape_index,
575  const unsigned int face_index) const
576 {
577  AssertIndexRange(shape_index, 2);
578  return (face_index == shape_index);
579 }
580 
581 
582 
583 template <int spacedim>
584 std::vector<unsigned int>
586 {
587  std::vector<unsigned int> dpo(2, 0U);
588  dpo[0] = 1;
589  return dpo;
590 }
591 
592 
593 
594 template <int spacedim>
595 bool
597 {
598  return true;
599 }
600 
601 template <int spacedim>
602 std::vector<std::pair<unsigned int, unsigned int> >
605 {
606  // this element is always discontinuous at vertices
607  return
608  std::vector<std::pair<unsigned int, unsigned int> > (1,std::make_pair(0U,0U));
609 }
610 
611 
612 
613 template <int spacedim>
614 std::vector<std::pair<unsigned int, unsigned int> >
617 {
618  // this element is continuous only for the highest dimensional bounding object
619  return
620  std::vector<std::pair<unsigned int, unsigned int> > ();
621 }
622 
623 
624 
625 template <int spacedim>
626 std::vector<std::pair<unsigned int, unsigned int> >
629 {
630  // this element is continuous only for the highest dimensional bounding object
631  return
632  std::vector<std::pair<unsigned int, unsigned int> > ();
633 }
634 
635 
636 
637 template <int spacedim>
641 {
643 }
644 
645 
646 
647 template <int spacedim>
648 std::pair<Table<2,bool>, std::vector<unsigned int> >
650 {
651  Table<2,bool> constant_modes(1, this->dofs_per_cell);
652  for (unsigned int i=0; i<this->dofs_per_cell; ++i)
653  constant_modes(0,i) = true;
654  return std::pair<Table<2,bool>, std::vector<unsigned int> >
655  (constant_modes, std::vector<unsigned int>(1,0));
656 }
657 
658 
659 
660 template <int spacedim>
663 {
664  UpdateFlags out = flags & update_values;
665  if (flags & update_gradients)
667  if (flags & update_hessians)
669  if (flags & update_normal_vectors)
671 
672  return out;
673 }
674 
675 
676 template <int spacedim>
677 void
681  const Quadrature<1> &,
682  const Mapping<1,spacedim> &,
683  const typename Mapping<1,spacedim>::InternalDataBase &,
684  const ::internal::FEValuesImplementation::MappingRelatedData<1, spacedim> &,
687 {
688  // Do nothing, since we do not have values in the interior
689 }
690 
691 
692 
693 template <int spacedim>
694 void
697  const unsigned int face,
698  const Quadrature<0> &,
699  const Mapping<1,spacedim> &,
700  const typename Mapping<1,spacedim>::InternalDataBase &,
701  const ::internal::FEValuesImplementation::MappingRelatedData<1, spacedim> &,
702  const typename FiniteElement<1,spacedim>::InternalDataBase &fe_internal,
704 {
705  const unsigned int foffset = face;
706  if (fe_internal.update_each & update_values)
707  {
708  for (unsigned int k=0; k<this->dofs_per_cell; ++k)
709  output_data.shape_values(k,0) = 0.;
710  output_data.shape_values(foffset,0) = 1;
711  }
712 }
713 
714 
715 template <int spacedim>
716 void
719  const unsigned int,
720  const unsigned int,
721  const Quadrature<0> &,
722  const Mapping<1,spacedim> &,
723  const typename Mapping<1,spacedim>::InternalDataBase &,
724  const ::internal::FEValuesImplementation::MappingRelatedData<1, spacedim> &,
727 {
728  Assert(false, ExcMessage("There are no sub-face values to fill in 1D!"));
729 }
730 
731 
732 
733 // --------------------------------------- FE_FaceP --------------------------
734 
735 template <int dim, int spacedim>
736 FE_FaceP<dim,spacedim>::FE_FaceP (const unsigned int degree)
737  :
738  FE_PolyFace<PolynomialSpace<dim-1>, dim, spacedim>
739  (PolynomialSpace<dim-1>(Polynomials::Legendre::generate_complete_basis(degree)),
740  FiniteElementData<dim>(get_dpo_vector(degree), 1, degree, FiniteElementData<dim>::L2),
741  std::vector<bool>(1,true))
742 {}
743 
744 
745 
746 template <int dim, int spacedim>
747 std::unique_ptr<FiniteElement<dim,spacedim> >
749 {
750  return std_cxx14::make_unique<FE_FaceP<dim,spacedim>>(this->degree);
751 }
752 
753 
754 
755 template <int dim, int spacedim>
756 std::string
758 {
759  // note that the FETools::get_fe_by_name function depends on the
760  // particular format of the string this function returns, so they have to be
761  // kept in synch
762  std::ostringstream namebuf;
763  namebuf << "FE_FaceP<"
764  << Utilities::dim_string(dim,spacedim)
765  << ">(" << this->degree << ")";
766 
767  return namebuf.str();
768 }
769 
770 
771 
772 template <int dim, int spacedim>
773 bool
775  const unsigned int shape_index,
776  const unsigned int face_index) const
777 {
778  return (face_index == (shape_index/this->dofs_per_face));
779 }
780 
781 
782 
783 template <int dim, int spacedim>
784 std::vector<unsigned int>
786 {
787  std::vector<unsigned int> dpo(dim+1, 0U);
788  dpo[dim-1] = deg+1;
789  for (unsigned int i=1; i<dim-1; ++i)
790  {
791  dpo[dim-1] *= deg+1+i;
792  dpo[dim-1] /= i+1;
793  }
794  return dpo;
795 }
796 
797 
798 
799 template <int dim, int spacedim>
800 bool
802 {
803  return true;
804 }
805 
806 
807 
808 template <int dim, int spacedim>
812 {
813  if (const FE_FaceP<dim,spacedim> *fe_q_other
814  = dynamic_cast<const FE_FaceP<dim,spacedim>*>(&fe_other))
815  {
816  if (this->degree < fe_q_other->degree)
818  else if (this->degree == fe_q_other->degree)
820  else
822  }
823  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
824  {
825  if (fe_nothing->is_dominating())
826  {
828  }
829  else
830  {
831  // the FE_Nothing has no degrees of freedom and it is typically used in
832  // a context where we don't require any continuity along the interface
834  }
835  }
836 
837  Assert (false, ExcNotImplemented());
839 }
840 
841 
842 
843 
844 template <int dim, int spacedim>
845 void
848  FullMatrix<double> &interpolation_matrix) const
849 {
850  get_subface_interpolation_matrix (source_fe, numbers::invalid_unsigned_int,
851  interpolation_matrix);
852 }
853 
854 
855 
856 template <int dim, int spacedim>
857 void
860  const unsigned int subface,
861  FullMatrix<double> &interpolation_matrix) const
862 {
863  // this function is similar to the respective method in FE_Q
864 
865  Assert (interpolation_matrix.n() == this->dofs_per_face,
866  ExcDimensionMismatch (interpolation_matrix.n(),
867  this->dofs_per_face));
868  Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
869  ExcDimensionMismatch (interpolation_matrix.m(),
870  x_source_fe.dofs_per_face));
871 
872  // see if source is a FaceP element
873  if (const FE_FaceP<dim,spacedim> *source_fe
874  = dynamic_cast<const FE_FaceP<dim,spacedim> *>(&x_source_fe))
875  {
876  // Make sure that the element for which the DoFs should be constrained
877  // is the one with the higher polynomial degree. Actually the procedure
878  // will work also if this assertion is not satisfied. But the matrices
879  // produced in that case might lead to problems in the hp procedures,
880  // which use this method.
881  Assert (this->dofs_per_face <= source_fe->dofs_per_face,
882  (typename FiniteElement<dim,spacedim>::
883  ExcInterpolationNotImplemented ()));
884 
885  // do this as in FETools by solving a least squares problem where we
886  // force the source FE polynomial to be equal the given FE on all
887  // quadrature points
888  const QGauss<dim-1> face_quadrature (source_fe->degree+1);
889 
890  // Rule of thumb for FP accuracy, that can be expected for a given
891  // polynomial degree. This value is used to cut off values close to
892  // zero.
893  const double eps = 2e-13*(this->degree+1)*(dim-1);
894 
895  FullMatrix<double> mass (face_quadrature.size(), source_fe->dofs_per_face);
896 
897  for (unsigned int k = 0; k < face_quadrature.size(); ++k)
898  {
899  const Point<dim-1> p =
900  subface == numbers::invalid_unsigned_int ?
901  face_quadrature.point(k) :
902  GeometryInfo<dim-1>::child_to_cell_coordinates (face_quadrature.point(k),
903  subface);
904 
905  for (unsigned int j = 0; j < source_fe->dofs_per_face; ++j)
906  mass (k, j) = source_fe->poly_space.compute_value(j, p);
907  }
908 
909  Householder<double> H(mass);
910  Vector<double> v_in(face_quadrature.size());
911  Vector<double> v_out(source_fe->dofs_per_face);
912 
913 
914  // compute the interpolation matrix by evaluating on the fine side and
915  // then solving the least squares problem
916  for (unsigned int i=0; i<this->dofs_per_face; ++i)
917  {
918  for (unsigned int k = 0; k < face_quadrature.size(); ++k)
919  {
920  const Point<dim-1> p = numbers::invalid_unsigned_int ?
921  face_quadrature.point(k) :
922  GeometryInfo<dim-1>::child_to_cell_coordinates (face_quadrature.point(k),
923  subface);
924  v_in(k) = this->poly_space.compute_value(i, p);
925  }
926  const double result = H.least_squares(v_out, v_in);
927  (void)result;
928  Assert(result < 1e-12, FETools::ExcLeastSquaresError (result));
929 
930  for (unsigned int j = 0; j < source_fe->dofs_per_face; ++j)
931  {
932  double matrix_entry = v_out(j);
933 
934  // Correct the interpolated value. I.e. if it is close to 1 or 0,
935  // make it exactly 1 or 0. Unfortunately, this is required to avoid
936  // problems with higher order elements.
937  if (std::fabs (matrix_entry - 1.0) < eps)
938  matrix_entry = 1.0;
939  if (std::fabs (matrix_entry) < eps)
940  matrix_entry = 0.0;
941 
942  interpolation_matrix(j,i) = matrix_entry;
943  }
944  }
945  }
946  else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != nullptr)
947  {
948  // nothing to do here, the FE_Nothing has no degrees of freedom anyway
949  }
950  else
951  AssertThrow (false,(typename FiniteElement<dim,spacedim>::
952  ExcInterpolationNotImplemented()));
953 }
954 
955 
956 
957 template <int dim, int spacedim>
958 std::pair<Table<2,bool>, std::vector<unsigned int> >
960 {
961  Table<2,bool> constant_modes(1, this->dofs_per_cell);
962  for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
963  constant_modes(0, face*this->dofs_per_face) = true;
964  return std::pair<Table<2,bool>, std::vector<unsigned int> >
965  (constant_modes, std::vector<unsigned int>(1, 0));
966 }
967 
968 
969 
970 template <int spacedim>
971 FE_FaceP<1,spacedim>::FE_FaceP (const unsigned int degree)
972  :
973  FE_FaceQ<1,spacedim> (degree)
974 {}
975 
976 
977 
978 template <int spacedim>
979 std::string
981 {
982  // note that the FETools::get_fe_by_name function depends on the
983  // particular format of the string this function returns, so they have to be
984  // kept in synch
985  std::ostringstream namebuf;
986  namebuf << "FE_FaceP<"
987  << Utilities::dim_string(1,spacedim)
988  << ">(" << this->degree << ")";
989 
990  return namebuf.str();
991 }
992 
993 
994 
995 // explicit instantiations
996 #include "fe_face.inst"
997 
998 
999 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 bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const
Definition: fe_face.cc:774
Transformed quadrature weights.
Shape function values.
size_type m() const
static const unsigned int invalid_unsigned_int
Definition: types.h:173
static ::ExceptionBase & ExcLeastSquaresError(double arg1)
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1248
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const
Definition: fe_face.cc:748
#define AssertIndexRange(index, range)
Definition: exceptions.h:1284
const unsigned int degree
Definition: fe_base.h:311
virtual FiniteElementDomination::Domination compare_for_face_domination(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe_face.cc:811
STL namespace.
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const
Definition: fe_face.cc:141
#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_face.cc:356
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix) const
Definition: fe_face.cc:153
Definition: point.h:104
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const
std::vector< Point< dim > > unit_support_points
Definition: fe.h:2413
static ::ExceptionBase & ExcMessage(std::string arg1)
size_type n() const
#define Assert(cond, exc)
Definition: exceptions.h:1142
UpdateFlags
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const
Definition: fe_face.cc:465
virtual std::string get_name() const
Definition: fe_face.cc:757
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
Abstract base class for mapping classes.
Definition: dof_tools.h:46
std::vector< Point< dim-1 > > unit_face_support_points
Definition: fe.h:2420
virtual bool hp_constraints_are_implemented() const
Definition: fe_face.cc:801
FE_FaceQ(const unsigned int p)
Definition: fe_face.cc:49
virtual void convert_generalized_support_point_values_to_dof_values(const std::vector< Vector< double > > &support_point_values, std::vector< double > &nodal_values) const
Definition: fe_face.cc:477
static std::vector< unsigned int > get_dpo_vector(const unsigned int deg)
Definition: fe_face.cc:785
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const
Definition: fe_face.cc:241
Second derivatives of shape functions.
std::string dim_string(const int dim, const int spacedim)
Definition: utilities.cc:176
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix) const
Definition: fe_face.cc:859
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe_face.cc:275
SymmetricTensor< rank, dim, Number > sum(const SymmetricTensor< rank, dim, Number > &local, const MPI_Comm &mpi_communicator)
const unsigned int dofs_per_cell
Definition: fe_base.h:295
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const
Definition: fe_face.cc:847
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const
Definition: fe_face.cc:114
Shape function gradients.
Normal vectors.
static std::vector< unsigned int > get_dpo_vector(const unsigned int deg)
Definition: fe_face.cc:252
const unsigned int dofs_per_face
Definition: fe_base.h:288
double least_squares(Vector< number2 > &dst, const Vector< number2 > &src) const
static ::ExceptionBase & ExcNotImplemented()
FE_FaceP(unsigned int p)
Definition: fe_face.cc:736
virtual std::string get_name() const
Definition: fe_face.cc:123
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const
Definition: fe_face.cc:959
Covariant transformation.
virtual FiniteElementDomination::Domination compare_for_face_domination(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe_face.cc:431
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe_face.cc:287
static ::ExceptionBase & ExcInternalError()
virtual bool hp_constraints_are_implemented() const
Definition: fe_face.cc:265