From 7514de5f7117679b46f7bc165b402fd7a8b142ee Mon Sep 17 00:00:00 2001
From: Kilian Weishaupt <kilian.weishaupt@iws.uni-stuttgart.de>
Date: Sun, 24 Mar 2019 19:13:11 +0100
Subject: [PATCH] [staggered] Add Newton convergence writer

---
 .../staggerednewtonconvergencewriter.hh       | 185 ++++++++++++++++++
 1 file changed, 185 insertions(+)
 create mode 100644 dumux/nonlinear/staggerednewtonconvergencewriter.hh

diff --git a/dumux/nonlinear/staggerednewtonconvergencewriter.hh b/dumux/nonlinear/staggerednewtonconvergencewriter.hh
new file mode 100644
index 0000000000..1cb85da200
--- /dev/null
+++ b/dumux/nonlinear/staggerednewtonconvergencewriter.hh
@@ -0,0 +1,185 @@
+// -*- 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 3 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
+ * \ingroup Nonlinear
+ * \brief This class provides the infrastructure to write the
+ *        convergence behaviour of the newton method for the
+ *        staggered discretization scheme into a VTK file.
+ */
+#ifndef DUMUX_STAGGERED_NEWTON_CONVERGENCE_WRITER_HH
+#define DUMUX_STAGGERED_NEWTON_CONVERGENCE_WRITER_HH
+
+#include <string>
+
+#include <dune/grid/io/file/vtk/vtksequencewriter.hh>
+#include <dumux/io/vtksequencewriter.hh>
+#include <dumux/io/pointcloudvtkwriter.hh>
+#include "newtonconvergencewriter.hh"
+
+namespace Dumux {
+
+/*!
+ * \ingroup Nonlinear
+ * \brief Writes the intermediate solutions for every Newton iteration (for staggered grid scheme)
+ * \note To use this create a shared_ptr to an instance of this class in the main file
+ *       and pass it to newton.solve(x, convergencewriter). You can use the reset method
+ *       to write out multiple Newton solves with a unique id, if you don't call use all
+ *       Newton iterations just come after each other in the pvd file.
+ */
+template <class FVGridGeometry, class SolutionVector>
+class StaggeredNewtonConvergenceWriter : public ConvergenceWriterInterface<SolutionVector>
+{
+    using GridView = typename FVGridGeometry::GridView;
+
+    using CellCenterSolutionVector = typename std::decay_t<decltype(std::declval<SolutionVector>()[FVGridGeometry::cellCenterIdx()])>;
+    using FaceSolutionVector = typename std::decay_t<decltype(std::declval<SolutionVector>()[FVGridGeometry::faceIdx()])>;
+
+    using Scalar = typename CellCenterSolutionVector::block_type::value_type;
+
+    static constexpr auto numEqCellCenter = CellCenterSolutionVector::block_type::dimension;
+    static constexpr auto numEqFace = FaceSolutionVector::block_type::dimension;
+
+    using Element = typename GridView::template Codim<0>::Entity;
+    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
+
+    static_assert(FVGridGeometry::discMethod == DiscretizationMethod::staggered,
+                  "This convergence writer does only work for the staggered method, use the NewtonConvergenceWriter instead");
+public:
+    /*!
+     * \brief Constructor
+     * \param fvGridGeometry The finite volume geometry on the grid view
+     * \param name Base name of the vtk output
+     */
+    StaggeredNewtonConvergenceWriter(const FVGridGeometry& fvGridGeometry,
+                                     const std::string& name = "newton_convergence")
+    : fvGridGeometry_(fvGridGeometry)
+    , ccWriter_(fvGridGeometry.gridView(), name, "", "")
+    , faceWriter_(std::make_shared<PointCloudVtkWriter<Scalar, GlobalPosition>>(coordinates_))
+    , faceSequenceWriter_(faceWriter_, name + "-face", "","",
+                          fvGridGeometry.gridView().comm().rank(),
+                          fvGridGeometry.gridView().comm().size())
+    {
+        resize();
+
+        for (int eqIdx = 0; eqIdx < numEqCellCenter; ++eqIdx)
+        {
+            ccWriter_.addCellData(xCellCenter_[eqIdx], "x_" + std::to_string(eqIdx));
+            ccWriter_.addCellData(deltaCellCenter_[eqIdx], "delta_" + std::to_string(eqIdx));
+            ccWriter_.addCellData(defCellCenter_[eqIdx], "defect_" + std::to_string(eqIdx));
+        }
+    }
+
+    //! Resizes the output fields. This has to be called whenever the grid changes
+    void resize()
+    {
+        const auto numCellCenterDofs = fvGridGeometry_.numCellCenterDofs();
+        const auto numFaceDofs = fvGridGeometry_.numFaceDofs();
+
+        // resize the cell center output fields
+        for (int eqIdx = 0; eqIdx < numEqCellCenter; ++eqIdx)
+        {
+            defCellCenter_[eqIdx].resize(numCellCenterDofs);
+            deltaCellCenter_[eqIdx].resize(numCellCenterDofs);
+            xCellCenter_[eqIdx].resize(numCellCenterDofs);
+        }
+
+        // resize the face output fields
+        for (int eqIdx = 0; eqIdx < numEqFace; ++eqIdx)
+        {
+            defFace_[eqIdx].resize(numFaceDofs);
+            deltaFace_[eqIdx].resize(numFaceDofs);
+            xFace_[eqIdx].resize(numFaceDofs);
+        }
+
+        coordinates_.resize(numFaceDofs);
+        for (auto&& facet : facets(fvGridGeometry_.gridView()))
+        {
+            const auto dofIdxGlobal = fvGridGeometry_.gridView().indexSet().index(facet);
+            coordinates_[dofIdxGlobal] = facet.geometry().center();
+        }
+    }
+
+    //! Reset the convergence writer for a possible next Newton step
+    //! You may set a different id in case you don't want the output to be overwritten by the next step
+    void reset(std::size_t newId = 0UL)
+    { id_ = newId; iteration_ = 0UL; }
+
+    void write(const SolutionVector& uLastIter,
+               const SolutionVector& deltaU,
+               const SolutionVector& residual) override
+    {
+        assert(uLastIter.size() == deltaU.size() && uLastIter.size() == residual.size());
+
+        for (std::size_t dofIdxGlobal = 0; dofIdxGlobal < deltaU[FVGridGeometry::cellCenterIdx()].size(); ++dofIdxGlobal)
+        {
+            for (int eqIdx = 0; eqIdx < numEqCellCenter; ++eqIdx)
+            {
+                xCellCenter_[eqIdx][dofIdxGlobal] = uLastIter[FVGridGeometry::cellCenterIdx()][dofIdxGlobal][eqIdx];
+                deltaCellCenter_[eqIdx][dofIdxGlobal] = - deltaU[FVGridGeometry::cellCenterIdx()][dofIdxGlobal][eqIdx];
+                defCellCenter_[eqIdx][dofIdxGlobal] = residual[FVGridGeometry::cellCenterIdx()][dofIdxGlobal][eqIdx];
+            }
+        }
+
+        for (int eqIdx = 0; eqIdx < numEqFace; ++eqIdx)
+        {
+            faceWriter_->addPointData(xFace_[eqIdx], "x_" + std::to_string(eqIdx));
+            faceWriter_->addPointData(deltaFace_[eqIdx], "delta_" + std::to_string(eqIdx));
+            faceWriter_->addPointData(defFace_[eqIdx], "defect_" + std::to_string(eqIdx));
+        }
+
+        for (std::size_t dofIdxGlobal = 0; dofIdxGlobal < deltaU[FVGridGeometry::faceIdx()].size(); ++dofIdxGlobal)
+        {
+            for (int eqIdx = 0; eqIdx < numEqFace; ++eqIdx)
+            {
+                xFace_[eqIdx][dofIdxGlobal] = uLastIter[FVGridGeometry::faceIdx()][dofIdxGlobal][eqIdx];
+                deltaFace_[eqIdx][dofIdxGlobal] = - deltaU[FVGridGeometry::faceIdx()][dofIdxGlobal][eqIdx];
+                defFace_[eqIdx][dofIdxGlobal] = residual[FVGridGeometry::faceIdx()][dofIdxGlobal][eqIdx];
+            }
+        }
+
+        ccWriter_.write(static_cast<double>(id_) + static_cast<double>(iteration_)/1000);
+        faceSequenceWriter_.write(static_cast<double>(id_) + static_cast<double>(iteration_)/1000);
+        ++iteration_;
+    }
+
+private:
+    std::size_t id_ = 0UL;
+    std::size_t iteration_ = 0UL;
+
+    const FVGridGeometry& fvGridGeometry_;
+
+    Dune::VTKSequenceWriter<GridView> ccWriter_;
+
+    std::vector<GlobalPosition> coordinates_;
+    std::shared_ptr<PointCloudVtkWriter<Scalar, GlobalPosition>> faceWriter_;
+    VTKSequenceWriter<PointCloudVtkWriter<Scalar, GlobalPosition>> faceSequenceWriter_;
+
+    std::array<std::vector<Scalar>, numEqCellCenter> defCellCenter_;
+    std::array<std::vector<Scalar>, numEqCellCenter> deltaCellCenter_;
+    std::array<std::vector<Scalar>, numEqCellCenter> xCellCenter_;
+
+    std::array<std::vector<Scalar>, numEqFace> defFace_;
+    std::array<std::vector<Scalar>, numEqFace> deltaFace_;
+    std::array<std::vector<Scalar>, numEqFace> xFace_;
+};
+
+} // end namespace Dumux
+
+#endif
-- 
GitLab