From 5e966a4a76304270fa44985061a15fe7164bb5ab Mon Sep 17 00:00:00 2001
From: Denis Davydov <davydden@gmail.com>
Date: Mon, 24 Aug 2015 17:31:57 +0200
Subject: [PATCH] introduce a parameter to allow FE_Nothing dominate other FEs

made other FEs to comply with the new FE_Nothing;
corrected documentation of FE_Nothing::compare_for_face_domination()
---
 doc/news/changes.h              |  9 +++++++++
 include/deal.II/fe/fe_nothing.h | 29 ++++++++++++++++++++++++-----
 source/fe/fe_bernstein.cc       | 15 +++++++++++----
 source/fe/fe_face.cc            | 30 ++++++++++++++++++++++--------
 source/fe/fe_nedelec.cc         | 15 +++++++++++++--
 source/fe/fe_nothing.cc         | 31 +++++++++++++++++++++++++++----
 source/fe/fe_q_base.cc          | 15 +++++++++++----
 source/fe/fe_q_hierarchical.cc  | 19 +++++++++++--------
 source/fe/fe_q_iso_q1.cc        | 15 +++++++++++----
 source/fe/fe_trace.cc           | 15 +++++++++++----
 10 files changed, 150 insertions(+), 43 deletions(-)

diff --git a/doc/news/changes.h b/doc/news/changes.h
index f78659debb..1828acb7af 100644
--- a/doc/news/changes.h
+++ b/doc/news/changes.h
@@ -235,6 +235,15 @@ inconvenience this causes.
 
 
 <ol>
+  <li> New: Introduce an option for FE_Nothing to dominate any other FE.
+  Therefore at interfaces where, for example, a Q1 meets an FE_Nothing,
+  we will force the traces of the two functions to be the same. Because the
+  FE_Nothing encodes a space that is zero everywhere, this means that the Q1
+  field will be forced to become zero at this interface.
+  <br>
+  (Denis Davydov, 2015/08/31)
+  </li>
+
   <li> New: Jacobian second and third derivatives are now computed by the mapping classes and can be
   accessed through FEValues in much the same way as the Jacobian and Jacobian gradient.
   <br>
diff --git a/include/deal.II/fe/fe_nothing.h b/include/deal.II/fe/fe_nothing.h
index 91b8212547..65bf2297aa 100644
--- a/include/deal.II/fe/fe_nothing.h
+++ b/include/deal.II/fe/fe_nothing.h
@@ -82,10 +82,18 @@ class FE_Nothing : public FiniteElement<dim,spacedim>
 public:
 
   /**
-   * Constructor. Argument denotes the number of components to give this
+   * Constructor. First argument denotes the number of components to give this
    * finite element (default = 1).
+   *
+   * Second argument decides whether FE_Nothing
+   * will dominate any other FE in compare_for_face_domination() (default = false).
+   * Therefore at interfaces where, for example, a Q1 meets an FE_Nothing,
+   * we will force the traces of the two functions to be the same. Because the
+   * FE_Nothing encodes a space that is zero everywhere, this means that the Q1
+   * field will be forced to become zero at this interface.
    */
-  FE_Nothing (const unsigned int n_components = 1);
+  FE_Nothing (const unsigned int n_components = 1,
+              const bool dominate = false);
 
   /**
    * A sort of virtual copy constructor. Some places in the library, for
@@ -205,9 +213,10 @@ public:
    * particular the
    * @ref hp_paper "hp paper".
    *
-   * In the current case, this element is always assumed to dominate, unless
-   * it is also of type FE_Nothing().  In that situation, either element can
-   * dominate.
+   * In the current case, this element is assumed to dominate if the second
+   * argument in the constructor @p dominate is true. When this argument is false
+   * and @p fe_other is also of type FE_Nothing(), either element can dominate.
+   * Otherwise there are no_requirements.
    */
   virtual
   FiniteElementDomination::Domination
@@ -261,6 +270,16 @@ public:
                                     const unsigned int index,
                                     FullMatrix<double>  &interpolation_matrix) const;
 
+  /**
+   * @return true if the FE dominates any other.
+   */
+  bool is_dominating() const;
+
+private:
+  /**
+   * If true, this element will dominate any other apart from itself in compare_for_face_domination();
+   */
+  const bool dominate;
 
 };
 
diff --git a/source/fe/fe_bernstein.cc b/source/fe/fe_bernstein.cc
index 72bb8a5918..fdba3c32af 100644
--- a/source/fe/fe_bernstein.cc
+++ b/source/fe/fe_bernstein.cc
@@ -236,11 +236,18 @@ FE_Bernstein<dim,spacedim>::compare_for_face_domination (const FiniteElement<dim
       else
         return FiniteElementDomination::other_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
-      // the FE_Nothing has no degrees of freedom and it is typically used in
-      // a context where we don't require any continuity along the interface
-      return FiniteElementDomination::no_requirements;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
diff --git a/source/fe/fe_face.cc b/source/fe/fe_face.cc
index b3d9e2db48..9732fab950 100644
--- a/source/fe/fe_face.cc
+++ b/source/fe/fe_face.cc
@@ -276,11 +276,18 @@ compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
       else
         return FiniteElementDomination::other_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
-      // the FE_Nothing has no degrees of freedom and it is typically used in
-      // a context where we don't require any continuity along the interface
-      return FiniteElementDomination::no_requirements;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
@@ -608,11 +615,18 @@ compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
       else
         return FiniteElementDomination::other_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
-      // the FE_Nothing has no degrees of freedom and it is typically used in
-      // a context where we don't require any continuity along the interface
-      return FiniteElementDomination::no_requirements;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
diff --git a/source/fe/fe_nedelec.cc b/source/fe/fe_nedelec.cc
index ac21bd9e8f..8934aaad24 100644
--- a/source/fe/fe_nedelec.cc
+++ b/source/fe/fe_nedelec.cc
@@ -2296,8 +2296,9 @@ FE_Nedelec<dim>::compare_for_face_domination (const FiniteElement<dim> &fe_other
       else
         return FiniteElementDomination::other_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
+      // TODO: ???
       // the FE_Nothing has no
       // degrees of
       // freedom. nevertheless, we
@@ -2308,7 +2309,17 @@ FE_Nedelec<dim>::compare_for_face_domination (const FiniteElement<dim> &fe_other
       // and rather allow the
       // function to be discontinuous
       // along the interface
-      return FiniteElementDomination::other_element_dominates;
+//      return FiniteElementDomination::other_element_dominates;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
diff --git a/source/fe/fe_nothing.cc b/source/fe/fe_nothing.cc
index fb3ea4497c..d122101c4d 100644
--- a/source/fe/fe_nothing.cc
+++ b/source/fe/fe_nothing.cc
@@ -28,14 +28,16 @@ namespace
 
 
 template <int dim, int spacedim>
-FE_Nothing<dim,spacedim>::FE_Nothing (const unsigned int n_components)
+FE_Nothing<dim,spacedim>::FE_Nothing (const unsigned int n_components,
+                                      const bool dominate)
   :
   FiniteElement<dim,spacedim>
   (FiniteElementData<dim>(std::vector<unsigned>(dim+1,0),
                           n_components, 0,
                           FiniteElementData<dim>::unknown),
    std::vector<bool>(),
-   std::vector<ComponentMask>() )
+   std::vector<ComponentMask>() ),
+  dominate(dominate)
 {
 // in most other elements we have to set up all sorts of stuff
 // here. there isn't much that we have to do here; in particular,
@@ -162,13 +164,34 @@ fill_fe_subface_values (const Mapping<dim,spacedim> & /*mapping*/,
   // leave data fields empty
 }
 
+template <int dim, int spacedim>
+bool
+FE_Nothing<dim,spacedim>::is_dominating() const
+{
+  return dominate;
+}
+
 
 template <int dim, int spacedim>
 FiniteElementDomination::Domination
 FE_Nothing<dim,spacedim> ::
-compare_for_face_domination (const FiniteElement<dim,spacedim> &) const
+compare_for_face_domination (const FiniteElement<dim,spacedim> &fe) const
 {
-  return FiniteElementDomination::no_requirements;
+  // if FE_Nothing does not dominate, there are no requirements
+  if (!dominate)
+    {
+      return FiniteElementDomination::no_requirements;
+    }
+  // if it does and the other is FE_Nothing, either can dominate
+  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe) != 0)
+    {
+      return FiniteElementDomination::either_element_can_dominate;
+    }
+  // otherwise we dominate whatever fe is provided
+  else
+    {
+      return FiniteElementDomination::this_element_dominates;
+    }
 }
 
 
diff --git a/source/fe/fe_q_base.cc b/source/fe/fe_q_base.cc
index f6eb9fdbdc..3c2b3d39e2 100644
--- a/source/fe/fe_q_base.cc
+++ b/source/fe/fe_q_base.cc
@@ -859,11 +859,18 @@ compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
       else
         return FiniteElementDomination::other_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
-      // the FE_Nothing has no degrees of freedom and it is typically used in
-      // a context where we don't require any continuity along the interface
-      return FiniteElementDomination::no_requirements;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
diff --git a/source/fe/fe_q_hierarchical.cc b/source/fe/fe_q_hierarchical.cc
index 98b151c4e4..a3a7641eaa 100644
--- a/source/fe/fe_q_hierarchical.cc
+++ b/source/fe/fe_q_hierarchical.cc
@@ -364,15 +364,18 @@ compare_for_face_domination (const FiniteElement<dim> &fe_other) const
       else
         return FiniteElementDomination::other_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
-      // the FE_Nothing has no
-      // degrees of freedom and it is
-      // typically used in a context
-      // where we don't require any
-      // continuity along the
-      // interface
-      return FiniteElementDomination::no_requirements;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
diff --git a/source/fe/fe_q_iso_q1.cc b/source/fe/fe_q_iso_q1.cc
index 5a154c4dde..35747b15e6 100644
--- a/source/fe/fe_q_iso_q1.cc
+++ b/source/fe/fe_q_iso_q1.cc
@@ -98,11 +98,18 @@ compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
       else
         return FiniteElementDomination::neither_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
-      // the FE_Nothing has no degrees of freedom and it is typically used in
-      // a context where we don't require any continuity along the interface
-      return FiniteElementDomination::no_requirements;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
diff --git a/source/fe/fe_trace.cc b/source/fe/fe_trace.cc
index 3d68c93ed0..87ed272a22 100644
--- a/source/fe/fe_trace.cc
+++ b/source/fe/fe_trace.cc
@@ -156,11 +156,18 @@ compare_for_face_domination (const FiniteElement<dim,spacedim> &fe_other) const
       else
         return FiniteElementDomination::other_element_dominates;
     }
-  else if (dynamic_cast<const FE_Nothing<dim>*>(&fe_other) != 0)
+  else if (const FE_Nothing<dim> *fe_nothing = dynamic_cast<const FE_Nothing<dim>*>(&fe_other))
     {
-      // the FE_Nothing has no degrees of freedom and it is typically used in
-      // a context where we don't require any continuity along the interface
-      return FiniteElementDomination::no_requirements;
+      if (fe_nothing->is_dominating())
+        {
+          return FiniteElementDomination::other_element_dominates;
+        }
+      else
+        {
+          // the FE_Nothing has no degrees of freedom and it is typically used in
+          // a context where we don't require any continuity along the interface
+          return FiniteElementDomination::no_requirements;
+        }
     }
 
   Assert (false, ExcNotImplemented());
-- 
2.39.5