From 49f431281b7f885e80e6abfaa52916c72366db8e Mon Sep 17 00:00:00 2001
From: Robert K <robertk@posteo.org>
Date: Sat, 20 Feb 2016 16:42:11 +0100
Subject: [PATCH] [cleanup] Unified LDG and BR1 fluxes.

---
 .../operator/fluxes/diffusion/averageflux.hh  | 355 --------------
 .../operator/fluxes/diffusion/fluxes.hh       |  38 +-
 .../operator/fluxes/diffusion/ldgflux.hh      | 458 +++++++-----------
 .../operator/fluxes/diffusion/parameters.hh   |   8 +-
 4 files changed, 218 insertions(+), 641 deletions(-)
 delete mode 100644 dune/fem-dg/operator/fluxes/diffusion/averageflux.hh

diff --git a/dune/fem-dg/operator/fluxes/diffusion/averageflux.hh b/dune/fem-dg/operator/fluxes/diffusion/averageflux.hh
deleted file mode 100644
index c6425147..00000000
--- a/dune/fem-dg/operator/fluxes/diffusion/averageflux.hh
+++ /dev/null
@@ -1,355 +0,0 @@
-#ifndef DUNE_FEM_DG_LDGAVERAGEFLUX_HH
-#define DUNE_FEM_DG_LDGAVERAGEFLUX_HH
-
-// local includes
-#include "fluxbase.hh"
-
-namespace Dune
-{
-namespace Fem
-{
-
-  /**
-   * \brief A diffusion flux for the LDG scheme.
-   *
-   * \ingroup DiffusionFluxes
-   */
-  template <class DiscreteFunctionSpaceImp,
-            class ModelImp,
-            class FluxParameterImp >
-  class LDGAverageDiffusionFlux :
-    public LDGDiffusionFluxBase< DiscreteFunctionSpaceImp, ModelImp, FluxParameterImp >
-  {
-    typedef LDGDiffusionFluxBase< DiscreteFunctionSpaceImp, ModelImp, FluxParameterImp > BaseType;
-  public:
-    typedef DiscreteFunctionSpaceImp DiscreteFunctionSpaceType;
-
-    enum { dimDomain = DiscreteFunctionSpaceType :: dimDomain };
-    enum { dimRange  = DiscreteFunctionSpaceType :: dimRange };
-
-    typedef typename DiscreteFunctionSpaceType :: DomainType           DomainType;
-    typedef typename DiscreteFunctionSpaceType :: RangeFieldType       RangeFieldType;
-    typedef typename DiscreteFunctionSpaceType :: DomainFieldType      DomainFieldType;
-    typedef typename DiscreteFunctionSpaceType :: RangeType            RangeType;
-    typedef typename DiscreteFunctionSpaceType :: JacobianRangeType    JacobianRangeType;
-
-    typedef FieldVector< DomainFieldType, dimDomain-1 > FaceDomainType;
-
-    typedef typename DiscreteFunctionSpaceType :: GridPartType         GridPartType;
-    typedef typename GridPartType :: IntersectionIteratorType          IntersectionIterator;
-    typedef typename IntersectionIterator :: Intersection              Intersection;
-    typedef typename GridPartType :: GridType                          GridType;
-    typedef typename DiscreteFunctionSpaceType :: EntityType           EntityType;
-    enum { dimGradRange = dimDomain * dimRange };
-    enum { polOrd = DiscreteFunctionSpaceType :: polynomialOrder };
-
-    typedef typename BaseType :: ParameterType  ParameterType;
-
-    // type of gradient space
-    typedef typename DiscreteFunctionSpaceType ::
-        template ToNewDimRange< dimGradRange > :: Type   DiscreteGradientSpaceType;
-
-    typedef typename DiscreteGradientSpaceType :: RangeType GradientRangeType;
-    typedef typename DiscreteGradientSpaceType :: JacobianRangeType GradientJacobianType;
-
-    // jacobians of the functions do not have to be evaluated for this flux
-    enum { evaluateJacobian = false };
-
-  protected:
-    using BaseType::determineDirection;
-    using BaseType::model_;
-    using BaseType::cflDiffinv_;
-    using BaseType::numericalFlux ;
-    using BaseType::parameter ;
-    using BaseType::nonconformingFactor_;
-    using BaseType::dimensionFactor_;
-
-  public:
-    /**
-     * \brief constructor
-     */
-    LDGAverageDiffusionFlux(GridPartType& gridPart,
-                            const ModelImp& mod,
-                            const ParameterType& param ) :
-      BaseType( gridPart, mod, param ),
-      penalty_( parameter().penalty() ),
-      // Set CFL number for penalty term (compare diffusion in first pass)
-      penaltyTerm_( std::abs(  penalty_ ) > 0 )
-    {
-      if( Fem::Parameter::verbose () )
-      {
-        std::cout << "LDGAverageDiffusionFlux: penalty = " << penalty_ << std::endl;
-      }
-    }
-
-    LDGAverageDiffusionFlux(const LDGAverageDiffusionFlux& other)
-      : BaseType( other ),
-        penalty_( other.penalty_ ),
-        penaltyTerm_( other.penaltyTerm_ )
-    {}
-
-    //! returns true if lifting has to be calculated
-    const bool hasLifting () const { return false; }
-
-  protected:
-    enum { realLDG = true };
-    double theta( const DomainType& normal ) const
-    {
-      if( realLDG )
-      {
-        // LDG thete is 1 or 0
-        if( determineDirection( normal ) )
-          return 1.0;
-        else
-          return 0.0;
-      }
-      else
-        // Average fluxes
-        return 0.5;
-    }
-
-  public:
-    /**
-     * \brief flux function on interfaces between cells
-     *
-     * \param left local evaluation
-     * \param right local evaluation
-     * \param uLeft DOF evaluation on this side of \c intersection
-     * \param uRight DOF evaluation on the other side of \c intersection
-     * \param gLeft result for this side of \c intersection
-     * \param gRight result for the other side of \c intersection
-     * \return wave speed estimate (multiplied with the integration element of the intersection).
-     *         To estimate the time step |T|/wave is used
-     */
-    template <class LocalEvaluation>
-    double gradientNumericalFlux(const LocalEvaluation& left,
-                                 const LocalEvaluation& right,
-                                 const RangeType& uLeft,
-                                 const RangeType& uRight,
-                                 GradientRangeType& gLeft,
-                                 GradientRangeType& gRight,
-                                 GradientJacobianType& gDiffLeft,
-                                 GradientJacobianType& gDiffRight) const
-    {
-      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
-
-      // get factor for each side
-      const double thetaLeft  = theta( normal );
-      const double thetaRight = 1.0 - thetaLeft;
-
-      GradientJacobianType diffmatrix;
-
-      double diffTimeStep = 0.0;
-
-      // select left or right or average
-      if( thetaLeft > 0 )
-      {
-        //TODO use diffusionTimeStep
-        diffTimeStep = 0;
-
-        /* central differences (might be suboptimal) */
-        model_.jacobian(left, uLeft, diffmatrix );
-
-        diffmatrix.mv(normal, gLeft );
-        gLeft *= thetaLeft ;
-      }
-      else
-        gLeft = 0;
-
-      if( thetaRight > 0 )
-      {
-        //const double diffStepRight = 0;
-
-        // right jacobian
-        model_.jacobian( right, uRight, diffmatrix );
-
-        diffmatrix.mv(normal, gRight);
-
-        // add to flux
-        gLeft.axpy( thetaRight, gRight );
-
-        // diffTimeStep = std::max( diffTimeStep, diffStepRight );
-      }
-
-      // copy flux
-      gRight = gLeft;
-
-#ifndef NDEBUG
-      gDiffLeft = 0;
-      gDiffRight = 0;
-#endif
-
-      // upper bound for the next time step length
-      return diffTimeStep; // * cflDiffinv_;
-    }
-
-
-    template <class LocalEvaluation>
-    double gradientBoundaryFlux(const LocalEvaluation& left,
-                                const RangeType& uLeft,
-                                const RangeType& uBnd,
-                                GradientRangeType& gLeft,
-                                GradientJacobianType& gDiffLeft) const
-    {
-      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
-
-      // get factor for each side
-      const double thetaLeft  = theta( normal );
-      const double thetaRight = 1.0 - thetaLeft;
-
-      GradientJacobianType diffmatrix;
-
-      // calculate uVal
-      RangeType uVal( 0 );
-
-      // select u from uLeft and uRight
-      if( thetaLeft > 0 )
-        uVal.axpy( thetaLeft , uLeft );
-      if( thetaRight > 0 )
-        uVal.axpy( thetaRight, uBnd );
-
-      // compute jacobian of u
-      model_.jacobian(left, uVal, diffmatrix );
-
-      diffmatrix.mv(normal, gLeft);
-
-#ifndef NDEBUG
-      gDiffLeft = 0;
-#endif
-
-      //TODO use diffusionTimeStep
-      const double diffTimeStep = 0; // * cflDiffinv_;
-      return diffTimeStep;
-    }
-
-
-    /**
-     * \brief flux function on interfaces between cells
-     *
-     * \param left local evaluation
-     * \param right local evaluation
-     * \param uLeft DOF evaluation on this side of \c intersection
-     * \param uRight DOF evaluation on the other side of \c intersection
-     * \param gLeft result for this side of \c intersection
-     * \param gRight result for the other side of \c intersection
-     * \return wave speed estimate (multiplied with the integration element of the intersection).
-     *         To estimate the time step |T|/wave is used
-     */
-    template <class LocalEvaluation>
-    double numericalFlux(const LocalEvaluation& left,
-                         const LocalEvaluation& right,
-                         const RangeType& uLeft,
-                         const RangeType& uRight,
-                         const JacobianRangeType& sigmaLeft,
-                         const JacobianRangeType& sigmaRight,
-                         RangeType& gLeft,
-                         RangeType& gRight,
-                         JacobianRangeType& gDiffLeft, // not used here (only for primal passes)
-                         JacobianRangeType& gDiffRight )
-    {
-      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
-      const double faceLengthSqr = normal.two_norm2();
-
-      /**********************************
-       * Diffusion sigma Flux (Pass 2)  *
-       **********************************/
-      JacobianRangeType diffmatrix;
-
-      // diffusion for uLeft
-      model_.diffusion( left, uLeft, sigmaLeft, diffmatrix);
-
-      RangeType diffflux;
-      diffmatrix.mv(normal, diffflux);
-
-      // diffusion for uRight
-      model_.diffusion( right, uRight, sigmaRight, diffmatrix);
-      // add to diffflux
-      diffmatrix.umv(normal, diffflux);
-      diffflux *= 0.5;
-
-      const double faceVolumeEstimate = dimensionFactor_ *
-        (left.intersection().conforming() ? faceLengthSqr
-          : (nonconformingFactor_ * faceLengthSqr));
-
-      const double diffTimeLeft =
-        model_.diffusionTimeStep( left, faceVolumeEstimate, uLeft );
-
-      const double diffTimeRight =
-        model_.diffusionTimeStep( right, faceVolumeEstimate, uRight );
-
-      double diffTimeStep = std::max( diffTimeLeft, diffTimeRight );
-
-      // add penalty factor
-      const double factor = penalty_ * diffTimeStep ;
-
-      RangeType jump( uLeft );
-      jump -= uRight;
-      diffflux.axpy(factor, jump);
-
-      gLeft  = diffflux;
-      gRight = diffflux;
-
-#ifndef NDEBUG
-      gDiffLeft = 0;
-      gDiffRight = 0;
-#endif
-
-      // timestep restict to diffusion timestep
-      // WARNING: reconsider this
-      diffTimeStep *= cflDiffinv_;
-      return diffTimeStep;
-    }
-
-
-    /**
-     * \brief same as numericalFlux() but for fluxes over boundary interfaces
-     */
-    template <class LocalEvaluation>
-    double boundaryFlux(const LocalEvaluation& left,
-                        const RangeType& uLeft,
-                        const RangeType& uRight,
-                        const JacobianRangeType& sigmaLeft,
-                        RangeType& gLeft,
-                        JacobianRangeType& gDiffLeft )
-    {
-      // get local point
-      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
-      const double faceLengthSqr = normal.two_norm2();
-
-      /****************************/
-      /* Diffusion (Pass 2)       */
-      /****************************/
-      JacobianRangeType diffmatrix;
-
-      model_.diffusion(left, uLeft, sigmaLeft, diffmatrix);
-
-      diffmatrix.mv(normal, gLeft);
-
-      const double faceVolumeEstimate = dimensionFactor_ * faceLengthSqr;
-
-      double diffTimeStep =
-        model_.diffusionTimeStep( left, faceVolumeEstimate, uLeft );
-
-      // add penalty term
-      const double factor = penalty_ * diffTimeStep;
-
-      RangeType jump( uLeft );
-      jump -= uRight;
-      gLeft.axpy(factor,jump);
-
-#ifndef NDEBUG
-      gDiffLeft = 0;
-#endif
-
-      diffTimeStep *= cflDiffinv_;
-      return diffTimeStep;
-    }
-  protected:
-    const double penalty_;
-    const bool penaltyTerm_;
-
-  }; // end LDGAverageDiffusionFlux
-
-} // end namespace
-} // end namespace
-#endif
diff --git a/dune/fem-dg/operator/fluxes/diffusion/fluxes.hh b/dune/fem-dg/operator/fluxes/diffusion/fluxes.hh
index 12ad3073..3a4494e5 100644
--- a/dune/fem-dg/operator/fluxes/diffusion/fluxes.hh
+++ b/dune/fem-dg/operator/fluxes/diffusion/fluxes.hh
@@ -4,7 +4,6 @@
 #include "fluxbase.hh"
 #include "dgprimalfluxes.hh"
 #include "ldgflux.hh"
-#include "averageflux.hh"
 
 namespace Dune
 {
@@ -227,9 +226,9 @@ namespace Fem
   template <class DiscreteFunctionSpaceImp,
             class Model>
   class DGDualDiffusionFlux<  DiscreteFunctionSpaceImp, Model, DualDiffusionFlux::Enum::average >
-    : public LDGAverageDiffusionFlux< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
+    : public LDGDiffusionFluxImpl< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
   {
-    typedef LDGAverageDiffusionFlux< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
+    typedef LDGDiffusionFluxImpl< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
       BaseType;
 
   public:
@@ -243,7 +242,7 @@ namespace Fem
     DGDualDiffusionFlux( GridPartType& gridPart,
                            const Model& model,
                            const ParameterType& parameters = ParameterType() )
-      : BaseType( gridPart, model, parameters  )
+      : BaseType( gridPart, model, parameters, DualDiffusionFlux::Enum::average )
     {
     }
   };
@@ -251,9 +250,9 @@ namespace Fem
   template <class DiscreteFunctionSpaceImp,
             class Model>
   class DGDualDiffusionFlux<  DiscreteFunctionSpaceImp, Model, DualDiffusionFlux::Enum::ldg >
-    : public LDGDiffusionFlux< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
+    : public LDGDiffusionFluxImpl< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
   {
-    typedef LDGDiffusionFlux< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
+    typedef LDGDiffusionFluxImpl< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
       BaseType;
 
   public:
@@ -267,18 +266,35 @@ namespace Fem
     DGDualDiffusionFlux( GridPartType& gridPart,
                          const Model& model,
                          const ParameterType& parameters = ParameterType() )
-      : BaseType( gridPart, model, parameters  )
+      : BaseType( gridPart, model, parameters, DualDiffusionFlux::Enum::ldg )
     {
     }
   };
 
-  //TODO implement general case...
   template <class DiscreteFunctionSpaceImp,
             class Model>
   class DGDualDiffusionFlux<  DiscreteFunctionSpaceImp, Model, DualDiffusionFlux::Enum::general >
-  {};
+    : public LDGDiffusionFluxImpl< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
+  {
+    typedef LDGDiffusionFluxImpl< DiscreteFunctionSpaceImp, Model, DGDualDiffusionFluxParameters >
+      BaseType;
+
+  public:
+    typedef DiscreteFunctionSpaceImp                         DiscreteFunctionSpaceType;
+    typedef typename DiscreteFunctionSpaceType::GridPartType GridPartType;
+    typedef typename BaseType::ParameterType                 ParameterType;
 
+    /**
+      * \brief constructor reading parameters
+      */
+    DGDualDiffusionFlux( GridPartType& gridPart,
+                         const Model& model,
+                         const ParameterType& parameters = ParameterType() )
+      : BaseType( gridPart, model, parameters, DualDiffusionFlux::Enum::general )
+    {
+    }
+  };
 
-} // end namespace
-} // end namespace
+} // end namespace Fem
+} // end namespace Dune
 #endif
diff --git a/dune/fem-dg/operator/fluxes/diffusion/ldgflux.hh b/dune/fem-dg/operator/fluxes/diffusion/ldgflux.hh
index ba794bf3..a6b0a2ca 100644
--- a/dune/fem-dg/operator/fluxes/diffusion/ldgflux.hh
+++ b/dune/fem-dg/operator/fluxes/diffusion/ldgflux.hh
@@ -1,5 +1,5 @@
-#ifndef DUNE_FEM_DG_LDGFLUX_HH
-#define DUNE_FEM_DG_LDGFLUX_HH
+#ifndef DUNE_FEM_DG_LDGAVERAGEFLUX_HH
+#define DUNE_FEM_DG_LDGAVERAGEFLUX_HH
 
 // local includes
 #include "fluxbase.hh"
@@ -10,17 +10,17 @@ namespace Fem
 {
 
   /**
-   * \brief diffusion flux
+   * \brief Implementation of Bassi-Rebay 1 and Local DG fluxes.
    *
    * \ingroup DiffusionFluxes
    */
   template <class DiscreteFunctionSpaceImp,
             class ModelImp,
             class FluxParameterImp>
-  class LDGDiffusionFlux :
-    public DGDiffusionFluxBase< DiscreteFunctionSpaceImp, ModelImp, FluxParameterImp >
+  class LDGDiffusionFluxImpl :
+    public LDGDiffusionFluxBase< DiscreteFunctionSpaceImp, ModelImp, FluxParameterImp >
   {
-    typedef DGDiffusionFluxBase< DiscreteFunctionSpaceImp, ModelImp, FluxParameterImp > BaseType;
+    typedef LDGDiffusionFluxBase< DiscreteFunctionSpaceImp, ModelImp, FluxParameterImp > BaseType;
   public:
     typedef DiscreteFunctionSpaceImp DiscreteFunctionSpaceType;
 
@@ -46,7 +46,8 @@ namespace Fem
     typedef typename BaseType :: ParameterType  ParameterType;
 
     // type of gradient space
-    typedef typename BaseType :: DiscreteGradientSpaceType  DiscreteGradientSpaceType;
+    typedef typename DiscreteFunctionSpaceType ::
+        template ToNewDimRange< dimGradRange > :: Type   DiscreteGradientSpaceType;
 
     typedef typename DiscreteGradientSpaceType :: RangeType GradientRangeType;
     typedef typename DiscreteGradientSpaceType :: JacobianRangeType GradientJacobianType;
@@ -54,394 +55,309 @@ namespace Fem
     // jacobians of the functions do not have to be evaluated for this flux
     enum { evaluateJacobian = false };
 
-  private:
-    // no copying
-    LDGDiffusionFlux(const LDGDiffusionFlux& other);
   protected:
-    using BaseType :: determineDirection;
-    using BaseType :: model_;
-    using BaseType :: cflDiffinv_;
-    using BaseType :: dimensionFactor_;
-    using BaseType :: nonconformingFactor_;
-    using BaseType :: parameter;
+    typedef typename BaseType::IdEnum         EnumType;
+
+    using BaseType::determineDirection;
+    using BaseType::model_;
+    using BaseType::cflDiffinv_;
+    using BaseType::numericalFlux ;
+    using BaseType::parameter ;
+    using BaseType::nonconformingFactor_;
+    using BaseType::dimensionFactor_;
 
   public:
     /**
      * \brief constructor
      */
-    LDGDiffusionFlux(GridPartType& gridPart,
-                     const ModelImp& model,
-                     const ParameterType& parameters = ParameterType() )
-    : BaseType( model, true, parameters ),
+    LDGDiffusionFluxImpl(GridPartType& gridPart,
+                         const ModelImp& mod,
+                         const ParameterType& param,
+                         const EnumType staticMethod ) :
+      BaseType( gridPart, mod, param ),
+      method_( staticMethod == EnumType::general ? param.getMethod() : staticMethod ),
       penalty_( parameter().penalty() ),
       // Set CFL number for penalty term (compare diffusion in first pass)
       penaltyTerm_( std::abs(  penalty_ ) > 0 )
     {
       if( Fem::Parameter::verbose () )
       {
-        std::cout << "LDGDiffusionFlux: penalty = " << penalty_ << std::endl;
+        std::cout << "LDGDiffusionFluxImpl: penalty = " << penalty_ << std::endl;
       }
     }
 
+    LDGDiffusionFluxImpl(const LDGDiffusionFluxImpl& other)
+      : BaseType( other ),
+        method_( other.method_ ),
+        penalty_( other.penalty_ ),
+        penaltyTerm_( other.penaltyTerm_ )
+    {}
+
     //! returns true if lifting has to be calculated
-    bool hasLifting () const { return false; }
+    const bool hasLifting () const { return false; }
 
-    void diffusionFluxPenalty( std::ostream& out ) const
+  protected:
+    enum { realLDG = true };
+    double theta( const DomainType& normal ) const
     {
-      out <<penalty_;
+      if( method_ == EnumType::ldg )
+      {
+        // LDG thete is 1 or 0
+        if( determineDirection( normal ) )
+          return 1.0;
+        else
+          return 0.0;
+      }
+      else
+      {
+        assert( method_ == EnumType::br1 );
+        // Average fluxes (Bassi-Rebay 1)
+        return 0.5;
+      }
     }
 
   public:
     /**
      * \brief flux function on interfaces between cells
      *
-     * @param intersection intersection
-     * @param time current time given by TimeProvider
-     * @param x coordinate of required evaluation local to \c intersection
-     * @param uLeft DOF evaluation on this side of \c intersection
-     * @param uRight DOF evaluation on the other side of \c intersection
-     * @param gLeft result for this side of \c intersection
-     * @param gRight result for the other side of \c intersection
+     * \param left local evaluation
+     * \param right local evaluation
+     * \param uLeft DOF evaluation on this side of \c intersection
+     * \param uRight DOF evaluation on the other side of \c intersection
+     * \param gLeft result for this side of \c intersection
+     * \param gRight result for the other side of \c intersection
      * \return wave speed estimate (multiplied with the integration element of the intersection).
      *         To estimate the time step |T|/wave is used
      */
-    template <class QuadratureImp>
-    double gradientNumericalFlux(
-                        const Intersection& intersection,
-                        const EntityType& inside,
-                        const EntityType& outside,
-                        const double time,
-                        const QuadratureImp& faceQuadInner,
-                        const QuadratureImp& faceQuadOuter,
-                        const int quadPoint,
-                        const RangeType& uLeft,
-                        const RangeType& uRight,
-                        GradientRangeType& gLeft,
-                        GradientRangeType& gRight,
-                        GradientJacobianType& gDiffLeft,
-                        GradientJacobianType& gDiffRight) const
+    template <class LocalEvaluation>
+    double gradientNumericalFlux(const LocalEvaluation& left,
+                                 const LocalEvaluation& right,
+                                 const RangeType& uLeft,
+                                 const RangeType& uRight,
+                                 GradientRangeType& gLeft,
+                                 GradientRangeType& gRight,
+                                 GradientJacobianType& gDiffLeft,
+                                 GradientJacobianType& gDiffRight) const
     {
-      const FaceDomainType& x = faceQuadInner.localPoint( quadPoint );
-      const DomainType normal = intersection.integrationOuterNormal( x );
+      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
 
-      // determine side
-      const bool useInterior = determineDirection( normal );
+      // get factor for each side
+      const double thetaLeft  = theta( normal );
+      const double thetaRight = 1.0 - thetaLeft;
 
       GradientJacobianType diffmatrix;
 
-      if( useInterior )
+      double diffTimeStep = 0.0;
+
+      // select left or right or average
+      if( thetaLeft > 0 )
       {
-        model_.jacobian(inside,         /* inside entity */
-                        time,           /* for time dependent diffusion */
-                        faceQuadInner.point( quadPoint ),      /* inside point on intersection */
-                        uLeft,          /* { u_(x^-) } */
-                        diffmatrix      /* return diffusion tensor */
-                       );
+        //TODO use diffusionTimeStep
+        diffTimeStep = 0;
+
+        /* central differences (might be suboptimal) */
+        model_.jacobian(left, uLeft, diffmatrix );
+
+        diffmatrix.mv(normal, gLeft );
+        gLeft *= thetaLeft ;
       }
       else
+        gLeft = 0;
+
+      if( thetaRight > 0 )
       {
-        model_.jacobian(outside,       /* outside entity */
-                        time,          /* for time dependent diffusion */
-                        faceQuadOuter.point( quadPoint ),  /* outside point on intersection */
-                        uRight,        /* { u_(x^+) } */
-                        diffmatrix     /* return diffusion tensor */
-                       );
-      }
+        //const double diffStepRight = 0;
 
-      // mutliply with normal
-      diffmatrix.mv(normal, gLeft);
+        // right jacobian
+        model_.jacobian( right, uRight, diffmatrix );
+
+        diffmatrix.mv(normal, gRight);
+
+        // add to flux
+        gLeft.axpy( thetaRight, gRight );
+
+        // diffTimeStep = std::max( diffTimeStep, diffStepRight );
+      }
 
       // copy flux
       gRight = gLeft;
 
+#ifndef NDEBUG
       gDiffLeft = 0;
       gDiffRight = 0;
+#endif
 
-      // time step is set in 2nd pass
-      return 0.0;
+      // upper bound for the next time step length
+      return diffTimeStep; // * cflDiffinv_;
     }
 
-    /*
-     * \brief numerical flux for u given as u_h
-    */
-    template <class QuadratureImp>
-    double gradientBoundaryFlux(const Intersection& intersection,
-                                const EntityType& inside,
-                                const double time,
-                                const QuadratureImp& faceQuadInner,
-                                const int quadPoint,
+
+    template <class LocalEvaluation>
+    double gradientBoundaryFlux(const LocalEvaluation& left,
                                 const RangeType& uLeft,
                                 const RangeType& uBnd,
                                 GradientRangeType& gLeft,
                                 GradientJacobianType& gDiffLeft) const
     {
-      const FaceDomainType& x = faceQuadInner.localPoint( quadPoint );
-      const DomainType normal = intersection.integrationOuterNormal(x);
-      const DomainType& xglInside  = faceQuadInner.point( quadPoint );
+      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
+
+      // get factor for each side
+      const double thetaLeft  = theta( normal );
+      const double thetaRight = 1.0 - thetaLeft;
+
       GradientJacobianType diffmatrix;
 
-      // determine side
-      //const bool useInterior = determineDirection( normal );
+      // calculate uVal
+      RangeType uVal( 0 );
 
-      // get apropriate value
-      //const RangeType&  uVal = ( useInterior ) ? uLeft : uBnd ;
+      // select u from uLeft and uRight
+      if( thetaLeft > 0 )
+        uVal.axpy( thetaLeft , uLeft );
+      if( thetaRight > 0 )
+        uVal.axpy( thetaRight, uBnd );
 
-      // for the numerical diffusion flux \tilde u
-      // one uses \tilde u = g_D where g_D is Dirichlet boundary data
-      model_.jacobian( inside,
-                       time,
-                       xglInside,
-                       uBnd,
-                       diffmatrix
-                      );
+      // compute jacobian of u
+      model_.jacobian(left, uVal, diffmatrix );
 
-      // apply normal
       diffmatrix.mv(normal, gLeft);
 
-      // gDiffLeft is not needed for dual formalation (LDG)
+#ifndef NDEBUG
       gDiffLeft = 0;
+#endif
 
-      // time step is set in 2nd pass
-      return 0.0;
+      //TODO use diffusionTimeStep
+      const double diffTimeStep = 0; // * cflDiffinv_;
+      return diffTimeStep;
     }
 
 
     /**
      * \brief flux function on interfaces between cells
      *
-     * @param intersection intersection
-     * @param time current time given by TimeProvider
-     * @param x coordinate of required evaluation local to \c intersection
-     * @param uLeft DOF evaluation on this side of \c intersection
-     * @param uRight DOF evaluation on the other side of \c intersection
-     * @param gLeft result for this side of \c intersection
-     * @param gRight result for the other side of \c intersection
+     * \param left local evaluation
+     * \param right local evaluation
+     * \param uLeft DOF evaluation on this side of \c intersection
+     * \param uRight DOF evaluation on the other side of \c intersection
+     * \param gLeft result for this side of \c intersection
+     * \param gRight result for the other side of \c intersection
      * \return wave speed estimate (multiplied with the integration element of the intersection).
      *         To estimate the time step |T|/wave is used
      */
-    template <class DiscreteModelImp,
-              class QuadratureImp>
-    inline double numericalFlux(const Intersection& intersection,
-                         const DiscreteModelImp& discreteModel,
-                         const double time,
-                         const QuadratureImp& faceQuadInner,
-                         const QuadratureImp& faceQuadOuter,
-                         const int quadPoint,
-                         const RangeType& uLeft,
-                         const RangeType& uRight,
-                         const GradientRangeType& sigmaLeft,
-                         const GradientRangeType& sigmaRight,
-                         RangeType& gLeft,
-                         RangeType& gRight,
-                         JacobianRangeType& gDiffLeft, // not used here (only for primal passes)
-                         JacobianRangeType& gDiffRight ) const
-    {
-      Fem::FieldMatrixConverter< GradientRangeType, JacobianRangeType> jacLeft( sigmaLeft );
-      Fem::FieldMatrixConverter< GradientRangeType, JacobianRangeType> jacRight( sigmaRight );
-      return numericalFlux( intersection, discreteModel, time,
-                            faceQuadInner, faceQuadOuter, quadPoint,
-                            uLeft, uRight, jacLeft, jacRight,
-                            gLeft, gRight, gDiffLeft, gDiffRight );
-    }
-
-
-    template< class DiscreteModelImp,
-              class QuadratureImp, class JacobianRangeTypeImp >
-    double numericalFlux(const Intersection& intersection,
-                         const DiscreteModelImp& discreteModel,
-                         const double time,
-                         const QuadratureImp& faceQuadInner,
-                         const QuadratureImp& faceQuadOuter,
-                         const int quadPoint,
+    template <class LocalEvaluation>
+    double numericalFlux(const LocalEvaluation& left,
+                         const LocalEvaluation& right,
                          const RangeType& uLeft,
                          const RangeType& uRight,
-                         const JacobianRangeTypeImp& sigmaLeft,
-                         const JacobianRangeTypeImp& sigmaRight,
+                         const JacobianRangeType& sigmaLeft,
+                         const JacobianRangeType& sigmaRight,
                          RangeType& gLeft,
                          RangeType& gRight,
                          JacobianRangeType& gDiffLeft, // not used here (only for primal passes)
-                         JacobianRangeType& gDiffRight ) const
+                         JacobianRangeType& gDiffRight )
     {
-      const FaceDomainType& x = faceQuadInner.localPoint( quadPoint );
-      const DomainType normal = intersection.integrationOuterNormal(x);
-
-      const EntityType& inside  = discreteModel.inside();
-      const EntityType& outside = discreteModel.outside();
+      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
+      const double faceLengthSqr = normal.two_norm2();
 
-     /**********************************
-      * Diffusion sigma Flux (Pass 2)  *
-      **********************************/
+      /**********************************
+       * Diffusion sigma Flux (Pass 2)  *
+       **********************************/
       JacobianRangeType diffmatrix;
 
-      // determine side (needs to be opposite of above)
-      const bool useExterior = ! determineDirection( normal );
+      // diffusion for uLeft
+      model_.diffusion( left, uLeft, sigmaLeft, diffmatrix);
 
+      RangeType diffflux;
+      diffmatrix.mv(normal, diffflux);
 
-      if( useExterior )
-      {
-        model_.diffusion( inside, time,
-                          faceQuadInner.point( quadPoint ),
-                          uLeft, sigmaLeft, diffmatrix);
-      }
-      else
-      {
-        model_.diffusion( outside, time,
-                          faceQuadOuter.point( quadPoint ),
-                          uRight, sigmaRight, diffmatrix);
-      }
-
-      // apply normal
-      diffmatrix.mv(normal, gLeft);
-
-
-      //////////////////////////////////////////////////////////
-      //
-      //  --Time step calculation
-      //
-      //////////////////////////////////////////////////////////
-      const double faceLengthSqr = normal.two_norm2();
+      // diffusion for uRight
+      model_.diffusion( right, uRight, sigmaRight, diffmatrix);
+      // add to diffflux
+      diffmatrix.umv(normal, diffflux);
+      diffflux *= 0.5;
 
       const double faceVolumeEstimate = dimensionFactor_ *
-        ( intersection.conforming() ) ? faceLengthSqr : ( nonconformingFactor_ * faceLengthSqr );
+        (left.intersection().conforming() ? faceLengthSqr
+          : (nonconformingFactor_ * faceLengthSqr));
 
       const double diffTimeLeft =
-        model_.diffusionTimeStep( intersection,
-            discreteModel.enVolume(),
-            faceVolumeEstimate,
-            time, x, uLeft );
+        model_.diffusionTimeStep( left, faceVolumeEstimate, uLeft );
 
       const double diffTimeRight =
-        model_.diffusionTimeStep( intersection,
-            discreteModel.nbVolume(),
-            faceVolumeEstimate,
-            time, x, uRight );
-
-      //////////////////////////////////////////////////////////
-      //
-      //  --Penalty Term
-      //
-      //////////////////////////////////////////////////////////
-
-      // take minimum to proceed
-      const double diffTimeStep = std::max( diffTimeLeft, diffTimeRight );
-      if( penaltyTerm_ )
-      {
-        // add penalty term ( enVolume() is available since we derive from
-        //    DiscreteModelDefaultWithInsideOutside)
-        const double factor = penalty_ * diffTimeStep ;
+        model_.diffusionTimeStep( right, faceVolumeEstimate, uRight );
 
-        RangeType jump( uLeft );
-        jump -= uRight;
-        gLeft.axpy(factor, jump);
-      }
+      double diffTimeStep = std::max( diffTimeLeft, diffTimeRight );
+
+      // add penalty factor
+      const double factor = penalty_ * diffTimeStep ;
 
-      gRight = gLeft ;
+      RangeType jump( uLeft );
+      jump -= uRight;
+      diffflux.axpy(factor, jump);
 
-      // gDiffLeft should be 0 in case of LDG
+      gLeft  = diffflux;
+      gRight = diffflux;
+
+#ifndef NDEBUG
       gDiffLeft = 0;
       gDiffRight = 0;
+#endif
 
       // timestep restict to diffusion timestep
       // WARNING: reconsider this
-      return diffTimeStep * cflDiffinv_;
+      diffTimeStep *= cflDiffinv_;
+      return diffTimeStep;
     }
 
 
     /**
      * \brief same as numericalFlux() but for fluxes over boundary interfaces
      */
-    template <class DiscreteModelImp,
-              class QuadratureImp>
-    inline double boundaryFlux(const Intersection& intersection,
-                        const DiscreteModelImp& discreteModel,
-                        const double time,
-                        const QuadratureImp& faceQuadInner,
-                        const int quadPoint,
+    template <class LocalEvaluation>
+    double boundaryFlux(const LocalEvaluation& left,
                         const RangeType& uLeft,
                         const RangeType& uRight,
-                        const GradientRangeType& sigmaLeft,
+                        const JacobianRangeType& sigmaLeft,
                         RangeType& gLeft,
-                        JacobianRangeType& gDiffLeft) const   /*@LST0E@*/
-    {
-      Fem::FieldMatrixConverter< GradientRangeType, JacobianRangeType> jacLeft( sigmaLeft );
-      return boundaryFlux( intersection, discreteModel, time,
-                           faceQuadInner, quadPoint, uLeft, uRight,
-                           jacLeft, gLeft, gDiffLeft );
-    }
-
-    /**
-     * \brief same as numericalFlux() but for fluxes over boundary interfaces
-     */
-    template< class DiscreteModelImp,
-              class QuadratureImp, class JacobianRangeTypeImp >
-    double boundaryFlux(const Intersection& intersection,
-                        const DiscreteModelImp& discreteModel,
-                        const double time,
-                        const QuadratureImp& faceQuadInner,
-                        const int quadPoint,
-                        const RangeType& uLeft,
-                        const RangeType& uRight,
-                        const JacobianRangeTypeImp& sigmaLeft,
-                        RangeType& gLeft,
-                        JacobianRangeType& gDiffLeft) const   /*@LST0E@*/
+                        JacobianRangeType& gDiffLeft )
     {
       // get local point
-      const FaceDomainType& x = faceQuadInner.localPoint( quadPoint );
-      const DomainType normal = intersection.integrationOuterNormal(x);
-
-      const EntityType& inside  = discreteModel.inside();
+      const DomainType normal = left.intersection().integrationOuterNormal( left.localPosition() );
+      const double faceLengthSqr = normal.two_norm2();
 
       /****************************/
       /* Diffusion (Pass 2)       */
       /****************************/
       JacobianRangeType diffmatrix;
 
-      model_.diffusion(inside, time,
-                       faceQuadInner.point( quadPoint ),
-                       uLeft, sigmaLeft, diffmatrix);
+      model_.diffusion(left, uLeft, sigmaLeft, diffmatrix);
 
       diffmatrix.mv(normal, gLeft);
 
+      const double faceVolumeEstimate = dimensionFactor_ * faceLengthSqr;
 
-      //////////////////////////////////////////////////////////
-      //
-      //  --Time step calculation
-      //
-      //////////////////////////////////////////////////////////
-      const double faceVolumeEstimate = normal.two_norm2();
-
-      const double diffTimeStep =
-        model_.diffusionTimeStep( intersection,
-            discreteModel.enVolume(),
-            faceVolumeEstimate,
-            time, x, uLeft );
-
-      //////////////////////////////////////////////////////////
-      //
-      //  --Penalty Term
-      //
-      //////////////////////////////////////////////////////////
-      if( penaltyTerm_ )
-      {
-        // add penalty term
-        const double factor = penalty_ * diffTimeStep;
+      double diffTimeStep =
+        model_.diffusionTimeStep( left, faceVolumeEstimate, uLeft );
 
-        RangeType jump( uLeft );
-        jump -= uRight;
-        gLeft.axpy(factor, jump);
-      }
+      // add penalty term
+      const double factor = penalty_ * diffTimeStep;
+
+      RangeType jump( uLeft );
+      jump -= uRight;
+      gLeft.axpy(factor,jump);
 
-      // gDiffLeft should be 0 in case of LDG
+#ifndef NDEBUG
       gDiffLeft = 0;
+#endif
 
-      return diffTimeStep * cflDiffinv_;
+      diffTimeStep *= cflDiffinv_;
+      return diffTimeStep;
     }
-
   protected:
+    const EnumType method_;
     const double penalty_;
     const bool penaltyTerm_;
 
-  }; // end LDGDiffusionFlux
+  }; // end LDGDiffusionFluxImpl
 
 } // end namespace
 } // end namespace
diff --git a/dune/fem-dg/operator/fluxes/diffusion/parameters.hh b/dune/fem-dg/operator/fluxes/diffusion/parameters.hh
index 25231908..6605282a 100644
--- a/dune/fem-dg/operator/fluxes/diffusion/parameters.hh
+++ b/dune/fem-dg/operator/fluxes/diffusion/parameters.hh
@@ -40,7 +40,7 @@ namespace Fem
 
     //! Contains all known enums for primal diffusion fluxes which can be chosen via parameter file.
     const Enum        _enums[] = { Enum::cdg2, Enum::cdg, Enum::br2, Enum::ip, Enum::nipg, Enum::bo };
-    //! Contains all known names of primal diffusion fluxes which can be chosen via parameter file.
+    //! Contains all known names of primal DG diffusion fluxes which can be chosen via parameter file.
     const std::string _strings[] = { "CDG2", "CDG" , "BR2", "IP" , "NIPG", "BO" };
     //! Number of known primal diffusion fluxes which can be chosen via parameter file.
     static const int  _size = 6;
@@ -50,15 +50,15 @@ namespace Fem
   namespace DualDiffusionFlux
   {
     /**
-     * \brief Enum of all known primal diffusion flux implementations.
+     * \brief Enum of all known local DG diffusion flux implementations.
      *
      * \ingroup FemDGParameter
      */
     enum class Enum
     {
-      //! average theta flux.
+      //! Bassi-Rebay flux.
       average,
-      //! ldg flux.
+      //! Local DG flux.
       ldg,
       //! general flux: Parameter selection is done via parameter file!
       general,
-- 
GitLab