From 2472882ec06ce393bc01e76f3fecdc678e14bdf1 Mon Sep 17 00:00:00 2001
From: DennisGlaeser <dennis.glaeser@iws.uni-stuttgart.de>
Date: Thu, 25 Feb 2016 17:53:08 +0100
Subject: [PATCH] [ImplicitModel] Assembler adapted to the new structure

The assembler is now designed to work for all methods,
no extra classes for box and cc models are required
---
 dumux/implicit/assembler.hh | 461 ++++++++----------------------------
 1 file changed, 104 insertions(+), 357 deletions(-)

diff --git a/dumux/implicit/assembler.hh b/dumux/implicit/assembler.hh
index b2ab1c8f52..e0a0835044 100644
--- a/dumux/implicit/assembler.hh
+++ b/dumux/implicit/assembler.hh
@@ -59,47 +59,9 @@ class ImplicitAssembler
     ImplicitAssembler(const ImplicitAssembler &);
 
 public:
-    /*!
-     * \brief The colors of elements and vertices required for partial
-     *        Jacobian reassembly.
-     */
-    enum EntityColor {
-        /*!
-         * Vertex/element that needs to be reassembled because some
-         * relative error is above the tolerance
-         */
-        Red = 0,
-
-        /*!
-         * Vertex/element that needs to be reassembled because a
-         * neighboring element/vertex is red
-         */
-        Yellow = 1,
-
-        /*!
-         * Yellow vertex has only non-green neighbor elements.
-         *
-         * This means that its relative error is below the tolerance,
-         * but its defect can be linearized without any additional
-         * cost. This is just an "internal" color which is not used
-         * ouside of the jacobian assembler.
-         */
-        Orange = 2,
-
-        /*!
-         * Vertex/element that does not need to be reassembled
-         */
-        Green = 3
-    };
-
-    ImplicitAssembler()
-    : problemPtr_(0)
-    {
-        // set reassemble accuracy to 0, so that if partial reassembly
-        // of the jacobian matrix is disabled, the reassemble accuracy
-        // is always smaller than the current relative tolerance
-        reassembleAccuracy_ = 0.0;
-    }
+
+    ImplicitAssembler() : problemPtr_(nullptr)
+    {}
 
     /*!
      * \brief Initialize the jacobian assembler.
@@ -117,38 +79,11 @@ public:
         // initialize the BCRS matrix
         asImp_().createMatrix_();
 
-        // initialize the jacobian matrix and the right hand side
-        // vector
+        // initialize the jacobian matrix with zeros
         *matrix_ = 0;
-        reuseMatrix_ = false;
-
-        int numVertices = gridView_().size(dim);
-        int numElements = gridView_().size(0);
-        int numDofs = problem.model().numDofs();
-
-        residual_.resize(numDofs);
-
-        // initialize the storage part of the Jacobian matrix. Since
-        // we only need this if Jacobian matrix recycling is enabled,
-        // we do not waste space if it is disabled
-        if (enableJacobianRecycling_()) {
-            storageJacobian_.resize(numDofs);
-            storageTerm_.resize(numDofs);
-        }
 
-        if (gridView_().comm().size() > 1)
-            totalElems_ = gridView_().comm().sum(numElements);
-        else
-            totalElems_ = numElements;
-
-        // initialize data needed for partial reassembly
-        if (enablePartialReassemble_()) {
-            delta_.resize(numDofs);
-            elementColor_.resize(numElements);
-            if (isBox)
-                vertexColor_.resize(numVertices);
-        }
-        reassembleAll();
+        // allocate the residual vector
+        residual_.resize(problem.model().numDofs());
     }
 
     /*!
@@ -159,11 +94,10 @@ public:
      */
     void assemble()
     {
-        bool printReassembleStatistics = enablePartialReassemble_() && !reuseMatrix_;
-        int succeeded;
+        bool succeeded;
         try {
             asImp_().assemble_();
-            succeeded = 1;
+            succeeded = true;
             if (gridView_().comm().size() > 1)
                 succeeded = gridView_().comm().min(succeeded);
         }
@@ -172,7 +106,7 @@ public:
             std::cout << "rank " << problem_().gridView().comm().rank()
                       << " caught an exception while assembling:" << e.what()
                       << "\n";
-            succeeded = 0;
+            succeeded = false;
             if (gridView_().comm().size() > 1)
                 succeeded = gridView_().comm().min(succeeded);
         }
@@ -181,196 +115,6 @@ public:
             DUNE_THROW(NumericalProblem,
                        "A process did not succeed in linearizing the system");
         }
-
-        if (printReassembleStatistics)
-        {
-            if (gridView_().comm().size() > 1)
-            {
-                greenElems_ = gridView_().comm().sum(greenElems_);
-                reassembleAccuracy_ = gridView_().comm().max(nextReassembleAccuracy_);
-            }
-            else
-            {
-                reassembleAccuracy_ = nextReassembleAccuracy_;
-            }
-
-            problem_().newtonController().endIterMsg()
-                << ", reassembled "
-                << totalElems_ - greenElems_ << "/" << totalElems_
-                << " (" << 100*Scalar(totalElems_ - greenElems_)/totalElems_ << "%) elems @accuracy="
-                << reassembleAccuracy_;
-        }
-
-        // reset all vertex colors to green
-        for (unsigned int i = 0; i < vertexColor_.size(); ++i) {
-            vertexColor_[i] = Green;
-        }
-    }
-
-    /*!
-     * \brief If Jacobian matrix recycling is enabled, this method
-     *        specifies whether the next call to assemble() just
-     *        rescales the storage term or does a full reassembly
-     *
-     * \param yesno If true, only rescale; else do full Jacobian assembly.
-     */
-    void setMatrixReuseable(const bool yesno = true)
-    {
-        if (enableJacobianRecycling_())
-            reuseMatrix_ = yesno;
-    }
-
-    /*!
-     * \brief If partial Jacobian matrix reassembly is enabled, this
-     *        method causes all elements to be reassembled in the next
-     *        assemble() call.
-     */
-    void reassembleAll()
-    {
-        // do not reuse the current linearization
-        reuseMatrix_ = false;
-
-        // do not use partial reassembly for the next iteration
-        nextReassembleAccuracy_ = 0.0;
-        if (enablePartialReassemble_()) {
-            std::fill(vertexColor_.begin(),
-                      vertexColor_.end(),
-                      Red);
-            std::fill(elementColor_.begin(),
-                      elementColor_.end(),
-                      Red);
-            std::fill(delta_.begin(),
-                      delta_.end(),
-                      0.0);
-        }
-    }
-
-    /*!
-     * \brief Returns the largest relative error of a "green" vertex
-     *        for the most recent call of the assemble() method.
-     *
-     * This only has an effect if partial Jacobian reassembly is
-     * enabled. If it is disabled, then this method always returns 0.
-     *
-     * This returns the _actual_ relative computed seen by
-     * computeColors(), not the tolerance which it was given.
-     */
-    Scalar reassembleAccuracy() const
-    { return reassembleAccuracy_; }
-
-    /*!
-     * \brief Update the distance where the non-linear system was
-     *        originally insistently linearized and the point where it
-     *        will be linerized the next time.
-     *
-     * This only has an effect if partial reassemble is enabled.
-     */
-    void updateDiscrepancy(const SolutionVector &u,
-                           const SolutionVector &uDelta)
-    {
-        if (!enablePartialReassemble_())
-            return;
-
-        // update the vector with the distances of the current
-        // evaluation point used for linearization from the original
-        // evaluation point
-        for (unsigned int i = 0; i < delta_.size(); ++i) {
-            PrimaryVariables currentPriVars(u[i]);
-            PrimaryVariables nextPriVars(currentPriVars);
-            nextPriVars -= uDelta[i];
-
-            // we need to add the distance the solution was moved for
-            // this vertex
-            Scalar dist = model_().relativeShiftAtDof(currentPriVars,
-                                                      nextPriVars);
-            delta_[i] += std::abs(dist);
-        }
-
-    }
-
-    /*!
-     * \brief Force to reassemble a given degree of freedom
-     * next time the assemble() method is called.
-     *
-     * \param dofIdxGlobal The global index of the degree of freedom
-     */
-    void markDofRed(const int dofIdxGlobal)
-    {
-        if (!enablePartialReassemble_())
-            return;
-
-        if (isBox)
-            vertexColor_[dofIdxGlobal] = Red;
-        else
-            elementColor_[dofIdxGlobal] = Red;
-    }
-
-    /*!
-     * \brief Determine the colors of vertices and elements for partial
-     *        reassembly given a relative tolerance.
-     *
-     * \param relTol The relative error below which a vertex won't be
-     *               reassembled. Note that this specifies the
-     *               worst-case relative error between the last
-     *               linearization point and the current solution and
-     *               _not_ the delta vector of the Newton iteration!
-     */
-    void computeColors(const Scalar relTol)
-    {
-        asImp_().computeColors_(relTol);
-    }
-
-    /*!
-     * \brief Returns the reassemble color of a vertex
-     *
-     * \param element An element which contains the vertex
-     * \param vIdx The local index of the vertex in the element.
-     */
-    int vertexColor(const Element &element, const int vIdx) const
-    {
-        if (!enablePartialReassemble_())
-            return Red; // reassemble unconditionally!
-
-        int vIdxGlobal = vertexMapper_().subIndex(element, vIdx, dim);
-        return vertexColor_[vIdxGlobal];
-    }
-
-    /*!
-     * \brief Returns the reassemble color of a vertex
-     *
-     * \param vIdxGlobal The global index of the vertex.
-     */
-    int vertexColor(const int vIdxGlobal) const
-    {
-        if (!enablePartialReassemble_())
-            return Red; // reassemble unconditionally!
-        return vertexColor_[vIdxGlobal];
-    }
-
-    /*!
-     * \brief Returns the Jacobian reassemble color of an element
-     *
-     * \param element The Codim-0 DUNE entity
-     */
-    int elementColor(const Element &element) const
-    {
-        if (!enablePartialReassemble_())
-            return Red; // reassemble unconditionally!
-
-        int eIdxGlobal = elementMapper_().index(element);
-        return elementColor_[eIdxGlobal];
-    }
-
-    /*!
-     * \brief Returns the Jacobian reassemble color of an element
-     *
-     * \param globalElementIdx The global index of the element.
-     */
-    int elementColor(const int globalElementIdx) const
-    {
-        if (!enablePartialReassemble_())
-            return Red; // reassemble unconditionally!
-        return elementColor_[globalElementIdx];
     }
 
     /*!
@@ -390,60 +134,17 @@ public:
     { return residual_; }
 
 protected:
-    static bool enableJacobianRecycling_()
-    { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableJacobianRecycling); }
-    static bool enablePartialReassemble_()
-    { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnablePartialReassemble); }
-
 
     // reset the global linear system of equations. if partial
     // reassemble is enabled, this means that the jacobian matrix must
     // only be erased partially!
     void resetSystem_()
     {
-        // do not do anything if we can re-use the current linearization
-        if (reuseMatrix_)
-            return;
-
         // reset the right hand side.
         residual_ = 0.0;
 
-        if (!enablePartialReassemble_()) {
-            // If partial reassembly of the jacobian is not enabled,
-            // we can just reset everything!
-            (*matrix_) = 0;
-
-            // reset the parts needed for Jacobian recycling
-            if (enableJacobianRecycling_()) {
-                for (unsigned int i = 0; i < matrix_->N(); i++) {
-                    storageJacobian_[i] = 0;
-                    storageTerm_[i] = 0;
-                }
-            }
-
-            return;
-        }
-
-        // reset all entries corrosponding to a red or yellow vertex
-        for (unsigned int rowIdx = 0; rowIdx < matrix_->N(); ++rowIdx) {
-            if ((isBox && vertexColor_[rowIdx] != Green)
-                || (!isBox && elementColor_[rowIdx] != Green))
-            {
-                // reset the parts needed for Jacobian recycling
-                if (enableJacobianRecycling_()) {
-                    storageJacobian_[rowIdx] = 0;
-                    storageTerm_[rowIdx] = 0;
-                }
-
-                // set all matrix entries in the row to 0
-                typedef typename JacobianMatrix::ColIterator ColIterator;
-                ColIterator colIt = (*matrix_)[rowIdx].begin();
-                const ColIterator &colEndIt = (*matrix_)[rowIdx].end();
-                for (; colIt != colEndIt; ++colIt) {
-                    (*colIt) = 0.0;
-                }
-            }
-        }
+        // reset the matrix
+        (*matrix_) = 0;
     }
 
     // linearize the whole system
@@ -451,37 +152,6 @@ protected:
     {
         resetSystem_();
 
-        // if we can "recycle" the current linearization, we do it
-        // here and be done with it...
-        Scalar curDt = problem_().timeManager().timeStepSize();
-        if (reuseMatrix_) {
-            for (unsigned int i = 0; i < matrix_->N(); i++) {
-                // rescale the mass term of the jacobian matrix
-                MatrixBlock &J_i_i = (*matrix_)[i][i];
-
-                J_i_i -= storageJacobian_[i];
-                storageJacobian_[i] *= oldDt_/curDt;
-                J_i_i += storageJacobian_[i];
-
-                // use the flux term plus the source term as the new
-                // residual (since the delta in the d(storage)/dt is 0
-                // for the first iteration and the residual is
-                // approximately 0 in the last iteration, the flux
-                // term plus the source term must be equal to the
-                // negative change of the storage term of the last
-                // iteration of the last time step...)
-                residual_[i] = storageTerm_[i];
-                residual_[i] *= -1.0;
-            }
-
-            reuseMatrix_ = false;
-            oldDt_ = curDt;
-            return;
-        }
-
-        oldDt_ = curDt;
-        greenElems_ = 0;
-
         // reassemble the elements...
         for (const auto& element : elements(gridView_())) {
             if (element.partitionType() == Dune::GhostEntity)
@@ -495,6 +165,47 @@ protected:
         }
     }
 
+    // assemble an interior element
+    void assembleElement_(const Element &element)
+    {
+        model_().lLocalJacobian().assemble(element);
+
+        if (!isBox)
+        {
+            int globalI = elementMapper_().index(element);
+
+            // update the right hand side
+            residual_[globalI] = model_().localJacobian().residual(0);
+            for (int j = 0; j < residual_[globalI].dimension; ++j)
+                assert(std::isfinite(residual_[globalI][j]));
+
+            const auto& stencil = model_().stencils().elementStencil(element);
+
+            int j = 0;
+            for (auto&& globalJ : stencil)
+                (*matrix_)[globalI][globalJ] = model_().localJacobian().mat(0, j++);
+        }
+        else
+        {
+            DUNE_THROW(Dune::NotImplemented, "Box assembly");
+        }
+    }
+
+    // "assemble" a ghost element
+    void assembleGhostElement_(const Element &element)
+    {
+        int globalI = elementMapper_().index(element);
+
+        // update the right hand side
+        residual_[globalI] = 0.0;
+
+        // update the diagonal entry
+        typedef typename JacobianMatrix::block_type BlockType;
+        BlockType &J = (*matrix_)[globalI][globalI];
+        for (int j = 0; j < BlockType::rows; ++j)
+            J[j][j] = 1.0;
+    }
+
 protected:
     Problem &problem_()
     { return *problemPtr_; }
@@ -518,27 +229,63 @@ protected:
     // the right-hand side
     SolutionVector residual_;
 
-    // attributes required for jacobian matrix recycling
-    bool reuseMatrix_;
-    // The storage part of the local Jacobian
-    std::vector<MatrixBlock> storageJacobian_;
-    std::vector<VectorBlock> storageTerm_;
-    // time step size of last assembly
-    Scalar oldDt_;
+private:
 
+    // Construct the BCRS matrix for the global jacobian
+    void createMatrix_()
+    {
+        int numDofs = problem_().model().numDofs()
 
-    // attributes required for partial jacobian reassembly
-    std::vector<EntityColor> vertexColor_;
-    std::vector<EntityColor> elementColor_;
-    std::vector<Scalar> delta_;
+        // allocate raw matrix
+        matrix_ = std::make_shared<JacobianMatrix>(numDofs, numDofs, JacobianMatrix::random);
 
-    int totalElems_;
-    int greenElems_;
+        // set the row sizes
+        setRowSizes_();
 
-    Scalar nextReassembleAccuracy_;
-    Scalar reassembleAccuracy_;
+        // set the indices
+        addIndices_();
+    }
+
+    void setRowSizes_()
+    {
+        if (!isBox)
+        {
+            for (const auto& element : elements(gridview_()))
+            {
+                // the global index of the element at hand
+                const unsigned int elemIdx = elementMapper_().index(element);
+                const auto& stencil = model_().stencils().elementStencil(element);
+                matrix_->setrowsize(elemIdx, stencil.size());
+            }
+            matrix_->endrowsizes();
+        }
+        else
+        {
+            DUNE_THROW(Dune::NotImplemented, "Box Assmebly");
+        }
+    }
+
+    void addIndices_()
+    {
+        if (!isBox)
+        {
+            for (const auto& element : elements(gridview_()))
+            {
+                // the global index of the element at hand
+                const unsigned int globalI = elementMapper_().index(element);
+                const auto& stencil = model_().stencils().elementStencil(element);
+
+                for (globalJ : stencil)
+                    matrix_->addindex(globalI, globalJ);
+            }
+            matrix_->endrowsizes();
+        }
+        else
+        {
+            DUNE_THROW(Dune::NotImplemented, "Box Assmebly");
+        }
+    }
 
-private:
     Implementation &asImp_()
     { return *static_cast<Implementation*>(this); }
     const Implementation &asImp_() const
-- 
GitLab