Reference documentation for deal.II version 8.5.1
fe_raviart_thomas_nodal.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2003 - 2017 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_lib.h>
18 #include <deal.II/base/qprojector.h>
19 #include <deal.II/base/table.h>
20 #include <deal.II/grid/tria.h>
21 #include <deal.II/grid/tria_iterator.h>
22 #include <deal.II/dofs/dof_accessor.h>
23 #include <deal.II/fe/fe.h>
24 #include <deal.II/fe/mapping.h>
25 #include <deal.II/fe/fe_raviart_thomas.h>
26 #include <deal.II/fe/fe_values.h>
27 #include <deal.II/fe/fe_tools.h>
28 
29 #include <sstream>
30 
31 
32 DEAL_II_NAMESPACE_OPEN
33 
34 
35 template <int dim>
37  :
39  deg,
40  FiniteElementData<dim>(get_dpo_vector(deg),
41  dim, deg+1, FiniteElementData<dim>::Hdiv),
42  get_ria_vector (deg),
43  std::vector<ComponentMask>(PolynomialsRaviartThomas<dim>::compute_n_pols(deg),
44  std::vector<bool>(dim,true)))
45 {
46  Assert (dim >= 2, ExcImpossibleInDim(dim));
47  const unsigned int n_dofs = this->dofs_per_cell;
48 
50  // First, initialize the
51  // generalized support points and
52  // quadrature weights, since they
53  // are required for interpolation.
55 
56  // Now compute the inverse node matrix, generating the correct
57  // basis functions from the raw ones. For a discussion of what
58  // exactly happens here, see FETools::compute_node_matrix.
60  this->inverse_node_matrix.reinit(n_dofs, n_dofs);
61  this->inverse_node_matrix.invert(M);
62  // From now on, the shape functions provided by FiniteElement::shape_value
63  // and similar functions will be the correct ones, not
64  // the raw shape functions from the polynomial space anymore.
65 
66  // Reinit the vectors of
67  // prolongation matrices to the
68  // right sizes. There are no
69  // restriction matrices implemented
70  for (unsigned int ref_case=RefinementCase<dim>::cut_x;
71  ref_case<RefinementCase<dim>::isotropic_refinement+1; ++ref_case)
72  {
73  const unsigned int nc = GeometryInfo<dim>::n_children(RefinementCase<dim>(ref_case));
74 
75  for (unsigned int i=0; i<nc; ++i)
76  this->prolongation[ref_case-1][i].reinit (n_dofs, n_dofs);
77  }
78  // Fill prolongation matrices with embedding operators
80  // TODO[TL]: for anisotropic refinement we will probably need a table of submatrices with an array for each refine case
82  for (unsigned int i=0; i<GeometryInfo<dim>::max_children_per_face; ++i)
83  face_embeddings[i].reinit (this->dofs_per_face, this->dofs_per_face);
84  FETools::compute_face_embedding_matrices<dim,double>(*this, face_embeddings, 0, 0);
85  this->interface_constraints.reinit((1<<(dim-1)) * this->dofs_per_face,
86  this->dofs_per_face);
87  unsigned int target_row=0;
88  for (unsigned int d=0; d<GeometryInfo<dim>::max_children_per_face; ++d)
89  for (unsigned int i=0; i<face_embeddings[d].m(); ++i)
90  {
91  for (unsigned int j=0; j<face_embeddings[d].n(); ++j)
92  this->interface_constraints(target_row,j) = face_embeddings[d](i,j);
93  ++target_row;
94  }
95 }
96 
97 
98 
99 template <int dim>
100 std::string
102 {
103  // note that the
104  // FETools::get_fe_by_name
105  // function depends on the
106  // particular format of the string
107  // this function returns, so they
108  // have to be kept in synch
109 
110  // note that this->degree is the maximal
111  // polynomial degree and is thus one higher
112  // than the argument given to the
113  // constructor
114  std::ostringstream namebuf;
115  namebuf << "FE_RaviartThomasNodal<" << dim << ">(" << this->degree-1 << ")";
116 
117  return namebuf.str();
118 }
119 
120 
121 template <int dim>
124 {
125  return new FE_RaviartThomasNodal<dim>(*this);
126 }
127 
128 
129 //---------------------------------------------------------------------------
130 // Auxiliary and internal functions
131 //---------------------------------------------------------------------------
132 
133 
134 
135 template <int dim>
136 void
138 {
139  this->generalized_support_points.resize (this->dofs_per_cell);
140  this->generalized_face_support_points.resize (this->dofs_per_face);
141 
142  // Number of the point being entered
143  unsigned int current = 0;
144 
145  // On the faces, we choose as many
146  // Gauss points as necessary to
147  // determine the normal component
148  // uniquely. This is the deg of
149  // the Raviart-Thomas element plus
150  // one.
151  if (dim>1)
152  {
153  QGauss<dim-1> face_points (deg+1);
154  Assert (face_points.size() == this->dofs_per_face,
155  ExcInternalError());
156  for (unsigned int k=0; k<this->dofs_per_face; ++k)
157  this->generalized_face_support_points[k] = face_points.point(k);
159  for (unsigned int k=0;
160  k<this->dofs_per_face*GeometryInfo<dim>::faces_per_cell;
161  ++k)
162  this->generalized_support_points[k] = faces.point(k+QProjector<dim>
163  ::DataSetDescriptor::face(0,
164  true,
165  false,
166  false,
167  this->dofs_per_face));
168 
169  current = this->dofs_per_face*GeometryInfo<dim>::faces_per_cell;
170  }
171 
172  if (deg==0) return;
173  // In the interior, we need
174  // anisotropic Gauss quadratures,
175  // different for each direction.
176  QGauss<1> high(deg+1);
177  QGauss<1> low(deg);
178 
179  for (unsigned int d=0; d<dim; ++d)
180  {
181  QAnisotropic<dim> *quadrature;
182  if (dim == 1) quadrature = new QAnisotropic<dim>(high);
183  if (dim == 2) quadrature = new QAnisotropic<dim>(((d==0) ? low : high),
184  ((d==1) ? low : high));
185  if (dim == 3) quadrature = new QAnisotropic<dim>(((d==0) ? low : high),
186  ((d==1) ? low : high),
187  ((d==2) ? low : high));
188  Assert(dim<=3, ExcNotImplemented());
189 
190  for (unsigned int k=0; k<quadrature->size(); ++k)
191  this->generalized_support_points[current++] = quadrature->point(k);
192  delete quadrature;
193  }
194  Assert (current == this->dofs_per_cell, ExcInternalError());
195 }
196 
197 
198 
199 template <int dim>
200 std::vector<unsigned int>
202 {
203  // the element is face-based and we have
204  // (deg+1)^(dim-1) DoFs per face
205  unsigned int dofs_per_face = 1;
206  for (unsigned int d=1; d<dim; ++d)
207  dofs_per_face *= deg+1;
208 
209  // and then there are interior dofs
210  const unsigned int
211  interior_dofs = dim*deg*dofs_per_face;
212 
213  std::vector<unsigned int> dpo(dim+1);
214  dpo[dim-1] = dofs_per_face;
215  dpo[dim] = interior_dofs;
216 
217  return dpo;
218 }
219 
220 
221 
222 template <>
223 std::vector<bool>
224 FE_RaviartThomasNodal<1>::get_ria_vector (const unsigned int)
225 {
226  Assert (false, ExcImpossibleInDim(1));
227  return std::vector<bool>();
228 }
229 
230 
231 
232 template <int dim>
233 std::vector<bool>
235 {
236  const unsigned int dofs_per_cell = PolynomialsRaviartThomas<dim>::compute_n_pols(deg);
237  unsigned int dofs_per_face = deg+1;
238  for (unsigned int d=2; d<dim; ++d)
239  dofs_per_face *= deg+1;
240  // all face dofs need to be
241  // non-additive, since they have
242  // continuity requirements.
243  // however, the interior dofs are
244  // made additive
245  std::vector<bool> ret_val(dofs_per_cell,false);
246  for (unsigned int i=GeometryInfo<dim>::faces_per_cell*dofs_per_face;
247  i < dofs_per_cell; ++i)
248  ret_val[i] = true;
249 
250  return ret_val;
251 }
252 
253 
254 template <int dim>
255 bool
257  const unsigned int shape_index,
258  const unsigned int face_index) const
259 {
260  Assert (shape_index < this->dofs_per_cell,
261  ExcIndexRange (shape_index, 0, this->dofs_per_cell));
264 
265  // The first degrees of freedom are
266  // on the faces and each face has
267  // degree degrees.
268  const unsigned int support_face = shape_index / this->degree;
269 
270  // The only thing we know for sure
271  // is that shape functions with
272  // support on one face are zero on
273  // the opposite face.
274  if (support_face < GeometryInfo<dim>::faces_per_cell)
275  return (face_index != GeometryInfo<dim>::opposite_face[support_face]);
276 
277  // In all other cases, return true,
278  // which is safe
279  return true;
280 }
281 
282 
283 
284 template <int dim>
285 void
288  std::vector<double> &nodal_values) const
289 {
290  Assert (support_point_values.size() == this->generalized_support_points.size(),
291  ExcDimensionMismatch(support_point_values.size(), this->generalized_support_points.size()));
292  Assert (nodal_values.size() == this->dofs_per_cell,
293  ExcDimensionMismatch(nodal_values.size(),this->dofs_per_cell));
294  Assert (support_point_values[0].size() == this->n_components(),
295  ExcDimensionMismatch(support_point_values[0].size(),this->n_components()));
296 
297  // First do interpolation on
298  // faces. There, the component
299  // evaluated depends on the face
300  // direction and orientation.
301  unsigned int fbase = 0;
302  unsigned int f=0;
303  for (; f<GeometryInfo<dim>::faces_per_cell;
304  ++f, fbase+=this->dofs_per_face)
305  {
306  for (unsigned int i=0; i<this->dofs_per_face; ++i)
307  {
308  nodal_values[fbase+i] = support_point_values[fbase+i](GeometryInfo<dim>::unit_normal_direction[f]);
309  }
310  }
311 
312  // The remaining points form dim
313  // chunks, one for each component.
314  const unsigned int istep = (this->dofs_per_cell - fbase) / dim;
315  Assert ((this->dofs_per_cell - fbase) % dim == 0, ExcInternalError());
316 
317  f = 0;
318  while (fbase < this->dofs_per_cell)
319  {
320  for (unsigned int i=0; i<istep; ++i)
321  {
322  nodal_values[fbase+i] = support_point_values[fbase+i](f);
323  }
324  fbase+=istep;
325  ++f;
326  }
327  Assert (fbase == this->dofs_per_cell, ExcInternalError());
328 }
329 
330 
331 
332 template <int dim>
333 void
335  std::vector<double> &,
336  const std::vector<double> &) const
337 {
338  Assert(false, ExcNotImplemented());
339 }
340 
341 
342 template <int dim>
343 void
345  std::vector<double> &local_dofs,
346  const std::vector<Vector<double> > &values,
347  const unsigned int offset) const
348 {
349  Assert (values.size() == this->generalized_support_points.size(),
350  ExcDimensionMismatch(values.size(), this->generalized_support_points.size()));
351  Assert (local_dofs.size() == this->dofs_per_cell,
352  ExcDimensionMismatch(local_dofs.size(),this->dofs_per_cell));
353  Assert (values[0].size() >= offset+this->n_components(),
354  ExcDimensionMismatch(values[0].size(),offset+this->n_components()));
355 
356  // First do interpolation on
357  // faces. There, the component
358  // evaluated depends on the face
359  // direction and orientation.
360  unsigned int fbase = 0;
361  unsigned int f=0;
362  for (; f<GeometryInfo<dim>::faces_per_cell;
363  ++f, fbase+=this->dofs_per_face)
364  {
365  for (unsigned int i=0; i<this->dofs_per_face; ++i)
366  {
367  local_dofs[fbase+i] = values[fbase+i](offset+GeometryInfo<dim>::unit_normal_direction[f]);
368  }
369  }
370 
371  // The remaining points form dim
372  // chunks, one for each component.
373  const unsigned int istep = (this->dofs_per_cell - fbase) / dim;
374  Assert ((this->dofs_per_cell - fbase) % dim == 0, ExcInternalError());
375 
376  f = 0;
377  while (fbase < this->dofs_per_cell)
378  {
379  for (unsigned int i=0; i<istep; ++i)
380  {
381  local_dofs[fbase+i] = values[fbase+i](offset+f);
382  }
383  fbase+=istep;
384  ++f;
385  }
386  Assert (fbase == this->dofs_per_cell, ExcInternalError());
387 }
388 
389 
390 template <int dim>
391 void
393  std::vector<double> &local_dofs,
394  const VectorSlice<const std::vector<std::vector<double> > > &values) const
395 {
396  Assert (values.size() == this->n_components(),
397  ExcDimensionMismatch(values.size(), this->n_components()));
398  Assert (values[0].size() == this->generalized_support_points.size(),
399  ExcDimensionMismatch(values.size(), this->generalized_support_points.size()));
400  Assert (local_dofs.size() == this->dofs_per_cell,
401  ExcDimensionMismatch(local_dofs.size(),this->dofs_per_cell));
402  // First do interpolation on
403  // faces. There, the component
404  // evaluated depends on the face
405  // direction and orientation.
406  unsigned int fbase = 0;
407  unsigned int f=0;
408  for (; f<GeometryInfo<dim>::faces_per_cell;
409  ++f, fbase+=this->dofs_per_face)
410  {
411  for (unsigned int i=0; i<this->dofs_per_face; ++i)
412  {
413  local_dofs[fbase+i] = values[GeometryInfo<dim>::unit_normal_direction[f]][fbase+i];
414  }
415  }
416  // The remaining points form dim
417  // chunks, one for each component.
418  const unsigned int istep = (this->dofs_per_cell - fbase) / dim;
419  Assert ((this->dofs_per_cell - fbase) % dim == 0, ExcInternalError());
420 
421  f = 0;
422  while (fbase < this->dofs_per_cell)
423  {
424  for (unsigned int i=0; i<istep; ++i)
425  {
426  local_dofs[fbase+i] = values[f][fbase+i];
427  }
428  fbase+=istep;
429  ++f;
430  }
431  Assert (fbase == this->dofs_per_cell, ExcInternalError());
432 }
433 
434 
435 //TODO: There are tests that check that the following few functions don't produce assertion failures, but none that actually check whether they do the right thing. one example for such a test would be to project a function onto an hp space and make sure that the convergence order is correct with regard to the lowest used polynomial degree
436 
437 template <int dim>
438 bool
440 {
441  return true;
442 }
443 
444 
445 template <int dim>
446 std::vector<std::pair<unsigned int, unsigned int> >
448  const FiniteElement<dim> &fe_other) const
449 {
450  // we can presently only compute these
451  // identities if both FEs are
452  // FE_RaviartThomasNodals. in that case, no
453  // dofs are assigned on the vertex, so we
454  // shouldn't be getting here at all.
455  if (dynamic_cast<const FE_RaviartThomasNodal<dim>*>(&fe_other)!=0)
456  return std::vector<std::pair<unsigned int, unsigned int> > ();
457  else
458  {
459  Assert(false, ExcNotImplemented());
460  return std::vector<std::pair<unsigned int, unsigned int> > ();
461  }
462 }
463 
464 
465 
466 template <int dim>
467 std::vector<std::pair<unsigned int, unsigned int> >
469 hp_line_dof_identities (const FiniteElement<dim> &fe_other) const
470 {
471  // we can presently only compute
472  // these identities if both FEs are
473  // FE_RaviartThomasNodals
474  if (const FE_RaviartThomasNodal<dim> *fe_q_other
475  = dynamic_cast<const FE_RaviartThomasNodal<dim>*>(&fe_other))
476  {
477  // dofs are located on faces; these are
478  // only lines in 2d
479  if (dim != 2)
480  return std::vector<std::pair<unsigned int, unsigned int> >();
481 
482  // dofs are located along lines, so two
483  // dofs are identical only if in the
484  // following two cases (remember that
485  // the face support points are Gauss
486  // points):
487  //1. this->degree = fe_q_other->degree,
488  // in the case, all the dofs on
489  // the line are identical
490  //2. this->degree-1 and fe_q_other->degree-1
491  // are both even, i.e. this->dof_per_line
492  // and fe_q_other->dof_per_line are both odd,
493  // there exists only one point (the middle one)
494  // such that dofs are identical on this point
495  //
496  // to understand this, note that
497  // this->degree is the *maximal*
498  // polynomial degree, and is thus one
499  // higher than the argument given to
500  // the constructor
501  const unsigned int p = this->degree-1;
502  const unsigned int q = fe_q_other->degree-1;
503 
504  std::vector<std::pair<unsigned int, unsigned int> > identities;
505 
506  if (p==q)
507  for (unsigned int i=0; i<p+1; ++i)
508  identities.push_back (std::make_pair(i,i));
509 
510  else if (p%2==0 && q%2==0)
511  identities.push_back(std::make_pair(p/2,q/2));
512 
513  return identities;
514  }
515  else
516  {
517  Assert (false, ExcNotImplemented());
518  return std::vector<std::pair<unsigned int, unsigned int> > ();
519  }
520 }
521 
522 
523 template <int dim>
524 std::vector<std::pair<unsigned int, unsigned int> >
526  const FiniteElement<dim> &fe_other) const
527 {
528  // we can presently only compute
529  // these identities if both FEs are
530  // FE_RaviartThomasNodals
531  if (const FE_RaviartThomasNodal<dim> *fe_q_other
532  = dynamic_cast<const FE_RaviartThomasNodal<dim>*>(&fe_other))
533  {
534  // dofs are located on faces; these are
535  // only quads in 3d
536  if (dim != 3)
537  return std::vector<std::pair<unsigned int, unsigned int> >();
538 
539  // this works exactly like the line
540  // case above
541  const unsigned int p = this->dofs_per_quad;
542  const unsigned int q = fe_q_other->dofs_per_quad;
543 
544  std::vector<std::pair<unsigned int, unsigned int> > identities;
545 
546  if (p==q)
547  for (unsigned int i=0; i<p; ++i)
548  identities.push_back (std::make_pair(i,i));
549 
550  else if (p%2!=0 && q%2!=0)
551  identities.push_back(std::make_pair(p/2, q/2));
552 
553  return identities;
554  }
555  else
556  {
557  Assert (false, ExcNotImplemented());
558  return std::vector<std::pair<unsigned int, unsigned int> > ();
559  }
560 }
561 
562 
563 template <int dim>
566  const FiniteElement<dim> &fe_other) const
567 {
568  if (const FE_RaviartThomasNodal<dim> *fe_q_other
569  = dynamic_cast<const FE_RaviartThomasNodal<dim>*>(&fe_other))
570  {
571  if (this->degree < fe_q_other->degree)
573  else if (this->degree == fe_q_other->degree)
575  else
577  }
578 
579  Assert (false, ExcNotImplemented());
581 }
582 
583 
584 
585 template <>
586 void
588  const FiniteElement<1,1> &/*x_source_fe*/,
589  FullMatrix<double> &/*interpolation_matrix*/) const
590 {
591  Assert (false, ExcImpossibleInDim(1));
592 }
593 
594 
595 template <>
596 void
598  const FiniteElement<1,1> &/*x_source_fe*/,
599  const unsigned int /*subface*/,
600  FullMatrix<double> &/*interpolation_matrix*/) const
601 {
602  Assert (false, ExcImpossibleInDim(1));
603 }
604 
605 
606 
607 template <int dim>
608 void
610  const FiniteElement<dim> &x_source_fe,
611  FullMatrix<double> &interpolation_matrix) const
612 {
613  // this is only implemented, if the
614  // source FE is also a
615  // RaviartThomasNodal element
616  AssertThrow ((x_source_fe.get_name().find ("FE_RaviartThomasNodal<") == 0)
617  ||
618  (dynamic_cast<const FE_RaviartThomasNodal<dim>*>(&x_source_fe) != 0),
619  typename FiniteElement<dim>::
620  ExcInterpolationNotImplemented());
621 
622  Assert (interpolation_matrix.n() == this->dofs_per_face,
623  ExcDimensionMismatch (interpolation_matrix.n(),
624  this->dofs_per_face));
625  Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
626  ExcDimensionMismatch (interpolation_matrix.m(),
627  x_source_fe.dofs_per_face));
628 
629  // ok, source is a RaviartThomasNodal element, so
630  // we will be able to do the work
631  const FE_RaviartThomasNodal<dim> &source_fe
632  = dynamic_cast<const FE_RaviartThomasNodal<dim>&>(x_source_fe);
633 
634  // Make sure, that the element,
635  // for which the DoFs should be
636  // constrained is the one with
637  // the higher polynomial degree.
638  // Actually the procedure will work
639  // also if this assertion is not
640  // satisfied. But the matrices
641  // produced in that case might
642  // lead to problems in the
643  // hp procedures, which use this
644  // method.
645  Assert (this->dofs_per_face <= source_fe.dofs_per_face,
646  typename FiniteElement<dim>::
647  ExcInterpolationNotImplemented ());
648 
649  // generate a quadrature
650  // with the generalized support points.
651  // This is later based as a
652  // basis for the QProjector,
653  // which returns the support
654  // points on the face.
655  Quadrature<dim-1> quad_face_support (source_fe.get_generalized_face_support_points ());
656 
657  // Rule of thumb for FP accuracy,
658  // that can be expected for a
659  // given polynomial degree.
660  // This value is used to cut
661  // off values close to zero.
662  double eps = 2e-13*this->degree*(dim-1);
663 
664  // compute the interpolation
665  // matrix by simply taking the
666  // value at the support points.
667  const Quadrature<dim> face_projection
668  = QProjector<dim>::project_to_face (quad_face_support, 0);
669 
670  for (unsigned int i=0; i<source_fe.dofs_per_face; ++i)
671  {
672  const Point<dim> &p = face_projection.point (i);
673 
674  for (unsigned int j=0; j<this->dofs_per_face; ++j)
675  {
676  double matrix_entry
677  = this->shape_value_component (this->face_to_cell_index(j, 0),
678  p, 0);
679 
680  // Correct the interpolated
681  // value. I.e. if it is close
682  // to 1 or 0, make it exactly
683  // 1 or 0. Unfortunately, this
684  // is required to avoid problems
685  // with higher order elements.
686  if ( std::fabs(matrix_entry - 1.0) < eps )
687  matrix_entry = 1.0;
688  if ( std::fabs(matrix_entry) < eps )
689  matrix_entry = 0.0;
690 
691  interpolation_matrix(i,j) = matrix_entry;
692  }
693  }
694 
695  // make sure that the row sum of
696  // each of the matrices is 1 at
697  // this point. this must be so
698  // since the shape functions sum up
699  // to 1
700  for (unsigned int j=0; j<source_fe.dofs_per_face; ++j)
701  {
702  double sum = 0.;
703 
704  for (unsigned int i=0; i<this->dofs_per_face; ++i)
705  sum += interpolation_matrix(j,i);
706 
707  Assert (std::fabs(sum-1) < 2e-13*this->degree*(dim-1),
708  ExcInternalError());
709  }
710 }
711 
712 
713 template <int dim>
714 void
716  const FiniteElement<dim> &x_source_fe,
717  const unsigned int subface,
718  FullMatrix<double> &interpolation_matrix) const
719 {
720  // this is only implemented, if the
721  // source FE is also a
722  // RaviartThomasNodal element
723  AssertThrow ((x_source_fe.get_name().find ("FE_RaviartThomasNodal<") == 0)
724  ||
725  (dynamic_cast<const FE_RaviartThomasNodal<dim>*>(&x_source_fe) != 0),
726  typename FiniteElement<dim>::
727  ExcInterpolationNotImplemented());
728 
729  Assert (interpolation_matrix.n() == this->dofs_per_face,
730  ExcDimensionMismatch (interpolation_matrix.n(),
731  this->dofs_per_face));
732  Assert (interpolation_matrix.m() == x_source_fe.dofs_per_face,
733  ExcDimensionMismatch (interpolation_matrix.m(),
734  x_source_fe.dofs_per_face));
735 
736  // ok, source is a RaviartThomasNodal element, so
737  // we will be able to do the work
738  const FE_RaviartThomasNodal<dim> &source_fe
739  = dynamic_cast<const FE_RaviartThomasNodal<dim>&>(x_source_fe);
740 
741  // Make sure, that the element,
742  // for which the DoFs should be
743  // constrained is the one with
744  // the higher polynomial degree.
745  // Actually the procedure will work
746  // also if this assertion is not
747  // satisfied. But the matrices
748  // produced in that case might
749  // lead to problems in the
750  // hp procedures, which use this
751  // method.
752  Assert (this->dofs_per_face <= source_fe.dofs_per_face,
753  typename FiniteElement<dim>::
754  ExcInterpolationNotImplemented ());
755 
756  // generate a quadrature
757  // with the generalized support points.
758  // This is later based as a
759  // basis for the QProjector,
760  // which returns the support
761  // points on the face.
762  Quadrature<dim-1> quad_face_support (source_fe.get_generalized_face_support_points ());
763 
764  // Rule of thumb for FP accuracy,
765  // that can be expected for a
766  // given polynomial degree.
767  // This value is used to cut
768  // off values close to zero.
769  double eps = 2e-13*this->degree*(dim-1);
770 
771  // compute the interpolation
772  // matrix by simply taking the
773  // value at the support points.
774 
775  const Quadrature<dim> subface_projection
776  = QProjector<dim>::project_to_subface (quad_face_support, 0, subface);
777 
778  for (unsigned int i=0; i<source_fe.dofs_per_face; ++i)
779  {
780  const Point<dim> &p = subface_projection.point (i);
781 
782  for (unsigned int j=0; j<this->dofs_per_face; ++j)
783  {
784  double matrix_entry
785  = this->shape_value_component (this->face_to_cell_index(j, 0), p, 0);
786 
787  // Correct the interpolated
788  // value. I.e. if it is close
789  // to 1 or 0, make it exactly
790  // 1 or 0. Unfortunately, this
791  // is required to avoid problems
792  // with higher order elements.
793  if ( std::fabs(matrix_entry - 1.0) < eps )
794  matrix_entry = 1.0;
795  if ( std::fabs(matrix_entry) < eps )
796  matrix_entry = 0.0;
797 
798  interpolation_matrix(i,j) = matrix_entry;
799  }
800  }
801 
802  // make sure that the row sum of
803  // each of the matrices is 1 at
804  // this point. this must be so
805  // since the shape functions sum up
806  // to 1
807  for (unsigned int j=0; j<source_fe.dofs_per_face; ++j)
808  {
809  double sum = 0.;
810 
811  for (unsigned int i=0; i<this->dofs_per_face; ++i)
812  sum += interpolation_matrix(j,i);
813 
814  Assert (std::fabs(sum-1) < 2e-13*this->degree*(dim-1),
815  ExcInternalError());
816  }
817 }
818 
819 
820 
821 // explicit instantiations
822 #include "fe_raviart_thomas_nodal.inst"
823 
824 
825 DEAL_II_NAMESPACE_CLOSE
size_type m() const
virtual void convert_generalized_support_point_values_to_nodal_values(const std::vector< Vector< double > > &support_point_values, std::vector< double > &nodal_values) const
FullMatrix< double > interface_constraints
Definition: fe.h:2211
const std::vector< Point< dim-1 > > & get_generalized_face_support_points() const
Definition: fe.cc:1042
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
FE_RaviartThomasNodal(const unsigned int p)
virtual void interpolate(std::vector< double > &local_dofs, const std::vector< double > &values) const 1
const unsigned int dofs_per_quad
Definition: fe_base.h:250
const unsigned int degree
Definition: fe_base.h:311
const Point< dim > & point(const unsigned int i) const
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const
STL namespace.
void compute_embedding_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false, const double threshold=1.e-12)
Definition: fe_tools.cc:1897
static unsigned int compute_n_pols(unsigned int degree)
#define AssertThrow(cond, exc)
Definition: exceptions.h:369
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
static unsigned int n_children(const RefinementCase< dim > &refinement_case)
size_type n() const
std::vector< std::vector< FullMatrix< double > > > prolongation
Definition: fe.h:2199
virtual std::string get_name() const
void invert(const FullMatrix< number2 > &M)
void reinit(const TableIndices< N > &new_size, const bool omit_default_initialization=false)
#define Assert(cond, exc)
Definition: exceptions.h:313
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)
void initialize_support_points(const unsigned int rt_degree)
virtual std::string get_name() const =0
virtual bool hp_constraints_are_implemented() const
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
static Quadrature< dim > project_to_all_faces(const SubQuadrature &quadrature)
FullMatrix< double > compute_node_matrix(const FiniteElement< dim, spacedim > &fe)
Definition: fe_tools.cc:1616
static void project_to_face(const SubQuadrature &quadrature, const unsigned int face_no, std::vector< Point< dim > > &q_points)
const unsigned int dofs_per_face
Definition: fe_base.h:288
virtual FiniteElement< dim > * clone() const
static ::ExceptionBase & ExcNotImplemented()
unsigned int n_components(const DoFHandler< dim, spacedim > &dh)
static ::ExceptionBase & ExcInternalError()
static std::vector< bool > get_ria_vector(const unsigned int degree)