From 299ad420cc4c080d44390f01bacbd062a7967adc Mon Sep 17 00:00:00 2001
From: Timo Koch <timo.koch@iws.uni-stuttgart.de>
Date: Fri, 20 Oct 2017 17:36:23 +0200
Subject: [PATCH] Add pri var switch newton controller

---
 .../privarswitchnewtoncontroller.hh           | 200 ++++++++++++++++++
 1 file changed, 200 insertions(+)
 create mode 100644 dumux/porousmediumflow/compositional/privarswitchnewtoncontroller.hh

diff --git a/dumux/porousmediumflow/compositional/privarswitchnewtoncontroller.hh b/dumux/porousmediumflow/compositional/privarswitchnewtoncontroller.hh
new file mode 100644
index 0000000000..582e1df103
--- /dev/null
+++ b/dumux/porousmediumflow/compositional/privarswitchnewtoncontroller.hh
@@ -0,0 +1,200 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Reference implementation of a controller class for the Newton solver.
+ *
+ * Usually this controller should be sufficient.
+ */
+#ifndef DUMUX_PRIVARSWITCH_NEWTON_CONTROLLER_HH
+#define DUMUX_PRIVARSWITCH_NEWTON_CONTROLLER_HH
+
+#include <memory>
+#include <dune/common/hybridutilities.hh>
+#include <dumux/nonlinear/newtoncontroller.hh>
+
+namespace Dumux
+{
+
+/*!
+ * \ingroup Newton
+ * \brief A newton controller that handles primary variable switches
+ */
+template <class TypeTag>
+class PriVarSwitchNewtonController : public NewtonController<TypeTag>
+{
+    using ParentType = NewtonController<TypeTag>;
+    using Scalar =  typename GET_PROP_TYPE(TypeTag, Scalar);
+    using Implementation =  typename GET_PROP_TYPE(TypeTag, NewtonController);
+    using GridView =  typename GET_PROP_TYPE(TypeTag, GridView);
+    using Communicator = typename GridView::CollectiveCommunication;
+    using NumEqVector = typename GET_PROP_TYPE(TypeTag, NumEqVector);
+    using PrimaryVariableSwitch =  typename GET_PROP_TYPE(TypeTag, PrimaryVariableSwitch);
+    using ElementSolutionVector =  typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
+
+    static constexpr int numEq = GET_PROP_VALUE(TypeTag, NumEq);
+
+    enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) };
+
+public:
+    /*!
+     * \brief Constructor for stationary problems
+     */
+    PriVarSwitchNewtonController(const Communicator& comm)
+    : ParentType(comm)
+    , switchedInLastIteration_(false)
+    {}
+
+    /*!
+     * \brief Constructor for stationary problems
+     */
+    PriVarSwitchNewtonController(const Communicator& comm, std::shared_ptr<TimeLoop<Scalar>> timeLoop)
+    : ParentType(comm, timeLoop)
+    , switchedInLastIteration_(false)
+    {}
+
+    /*!
+     * \brief Returns true if the error of the solution is below the
+     *        tolerance.
+     */
+    bool newtonConverged() const
+    {
+        if (switchedInLastIteration_)
+            return false;
+
+        return ParentType::newtonConverged();
+    }
+
+    /*!
+     * \brief Called before the Newton method is applied to an
+     *        non-linear system of equations.
+     *
+     * \param u The initial solution
+     */
+    template<class SolutionVector>
+    void newtonBegin(const SolutionVector &u)
+    {
+        ParentType::newtonBegin(u);
+        priVarSwitch_ = std::make_unique<PrimaryVariableSwitch>(u.size());
+    }
+
+    /*!
+     * \brief Indicates that one Newton iteration was finished.
+     *
+     * \param assembler The jacobian assembler
+     * \param uCurrentIter The solution after the current Newton iteration
+     * \param uLastIter The solution at the beginning of the current Newton iteration
+     */
+    template<class JacobianAssembler, class SolutionVector>
+    void newtonEndStep(JacobianAssembler& assembler,
+                       SolutionVector &uCurrentIter,
+                       const SolutionVector &uLastIter)
+    {
+        ParentType::newtonEndStep(assembler, uCurrentIter, uLastIter);
+
+        // update the variable switch (returns true if the pri vars at at least one dof were switched)
+        // for disabled grid variable caching
+        const auto& fvGridGeometry = assembler.fvGridGeometry();
+        const auto& problem = assembler.problem();
+        auto& gridVariables = assembler.gridVariables();
+
+        switchedInLastIteration_ = priVarSwitch_->update(uCurrentIter, gridVariables,
+                                                         problem, fvGridGeometry);
+
+        Dune::Hybrid::ifElse(std::integral_constant<bool, GET_PROP_VALUE(TypeTag, EnableGlobalVolumeVariablesCache)>(),
+        [&](auto IF) {
+
+            std::cout << "blub";
+
+            // update the secondary variables if global caching is enabled
+            // \note we only updated if phase presence changed as the volume variables
+            //       are already updated once by the switch
+            for (const auto& element : elements(fvGridGeometry.gridView()))
+            {
+                // make sure FVElementGeometry & vol vars are bound to the element
+                auto fvGeometry = localView(fvGridGeometry);
+                fvGeometry.bindElement(element);
+
+                if (switchedInLastIteration_)
+                {
+                    for (auto&& scv : scvs(fvGeometry))
+                    {
+                        const auto dofIdxGlobal = scv.dofIndex();
+                        if (priVarSwitch_->wasSwitched(dofIdxGlobal))
+                        {
+                            const auto eIdx = fvGridGeometry.elementMapper().index(element);
+                            const auto elemSol = this->elementSolution(element, this->curSol());
+                            this->nonConstCurGlobalVolVars().volVars(eIdx, scv.indexInElement()).update(elemSol,
+                                                                                                        problem,
+                                                                                                        element,
+                                                                                                        scv);
+                        }
+                    }
+                }
+
+                // handle the boundary volume variables for cell-centered models
+                if(!isBox)
+                {
+                    for (auto&& scvf : scvfs(fvGeometry))
+                    {
+                        // if we are not on a boundary, skip the rest
+                        if (!scvf.boundary())
+                            continue;
+
+                        // check if boundary is a pure dirichlet boundary
+                        const auto bcTypes = problem.boundaryTypes(element, scvf);
+                        if (bcTypes.hasOnlyDirichlet())
+                        {
+                            const auto insideScvIdx = scvf.insideScvIdx();
+                            const auto& insideScv = fvGeometry.scv(insideScvIdx);
+                            const auto elemSol = ElementSolutionVector{problem.dirichlet(element, scvf)};
+
+                            this->nonConstCurGlobalVolVars().volVars(scvf.outsideScvIdx(), 0/*indexInElement*/).update(elemSol, problem, element, insideScv);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /*!
+     * \brief Called if the Newton method ended
+     *        (not known yet if we failed or succeeded)
+     */
+    void newtonEnd()
+    {
+        ParentType::newtonEnd();
+
+        // in any way, we have to reset the switch flag
+        switchedInLastIteration_ = false;
+        // free some memory
+        priVarSwitch_.release();
+    }
+
+private:
+
+    //! the class handling the primary variable switch
+    std::unique_ptr<PrimaryVariableSwitch> priVarSwitch_;
+    //! if we switched primary variables in the last iteration
+    bool switchedInLastIteration_;
+};
+
+} // end namespace Dumux
+
+#endif
-- 
GitLab