From 7a5a33de9a1f55c557ca7fc98d76f5d4ef204fd0 Mon Sep 17 00:00:00 2001
From: Timo Koch <timo.koch@iws.uni-stuttgart.de>
Date: Fri, 6 Jul 2018 20:05:22 +0200
Subject: [PATCH] [multidomain] Implement jacobian patterns for the coupling
 blocks

---
 dumux/multidomain/CMakeLists.txt             |   1 +
 dumux/multidomain/couplingjacobianpattern.hh | 173 +++++++++++++++++++
 2 files changed, 174 insertions(+)
 create mode 100644 dumux/multidomain/couplingjacobianpattern.hh

diff --git a/dumux/multidomain/CMakeLists.txt b/dumux/multidomain/CMakeLists.txt
index be647baaa6..705c536e73 100644
--- a/dumux/multidomain/CMakeLists.txt
+++ b/dumux/multidomain/CMakeLists.txt
@@ -1,4 +1,5 @@
 install(FILES
+couplingjacobianpattern.hh
 couplingmanager.hh
 newtonsolver.hh
 traits.hh
diff --git a/dumux/multidomain/couplingjacobianpattern.hh b/dumux/multidomain/couplingjacobianpattern.hh
new file mode 100644
index 0000000000..67f4cdf68a
--- /dev/null
+++ b/dumux/multidomain/couplingjacobianpattern.hh
@@ -0,0 +1,173 @@
+// -*- 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
+ * \ingroup Assembly
+ * \brief Helper function to generate Jacobian pattern for multidomain models
+ */
+#ifndef DUMUX_MUTLIDOMAIN_COUPLING_JACOBIAN_PATTERN_HH
+#define DUMUX_MUTLIDOMAIN_COUPLING_JACOBIAN_PATTERN_HH
+
+#include <type_traits>
+#include <dune/istl/matrixindexset.hh>
+#include <dumux/discretization/methods.hh>
+
+namespace Dumux {
+
+/*!
+ * \ingroup Assembly
+ * \brief Helper function to generate coupling Jacobian pattern (off-diagonal blocks)
+ *        for cell-centered schemes
+ */
+template<bool isImplicit, class CouplingManager, class GridGeometryI, class GridGeometryJ, std::size_t i, std::size_t j,
+         typename std::enable_if_t<( (GridGeometryI::discMethod == DiscretizationMethod::cctpfa)
+                                     || (GridGeometryI::discMethod == DiscretizationMethod::ccmpfa) ), int> = 0>
+Dune::MatrixIndexSet getCouplingJacobianPattern(const CouplingManager& couplingManager,
+                                                Dune::index_constant<i> domainI,
+                                                const GridGeometryI& gridGeometryI,
+                                                Dune::index_constant<j> domainJ,
+                                                const GridGeometryJ& gridGeometryJ)
+{
+    const auto numDofsI = gridGeometryI.numDofs();
+    const auto numDofsJ = gridGeometryJ.numDofs();
+    Dune::MatrixIndexSet pattern;
+    pattern.resize(numDofsI, numDofsJ);
+
+    // matrix pattern for implicit Jacobians
+    if (isImplicit)
+    {
+        for (const auto& elementI : elements(gridGeometryI.gridView()))
+        {
+            const auto& stencil = couplingManager.couplingStencil(domainI, elementI, domainJ);
+            const auto globalI = gridGeometryI.elementMapper().index(elementI);
+            for (const auto globalJ : stencil)
+                pattern.add(globalI, globalJ);
+        }
+    }
+
+    // matrix pattern for explicit Jacobians
+    // -> diagonal matrix, so coupling block is empty
+    // just return the empty pattern
+
+    return pattern;
+}
+
+/*!
+ * \ingroup Assembly
+ * \brief Helper function to generate coupling Jacobian pattern (off-diagonal blocks)
+ *        for the box scheme
+ */
+template<bool isImplicit, class CouplingManager, class GridGeometryI, class GridGeometryJ, std::size_t i, std::size_t j,
+         typename std::enable_if_t<(GridGeometryI::discMethod == DiscretizationMethod::box), int> = 0>
+Dune::MatrixIndexSet getCouplingJacobianPattern(const CouplingManager& couplingManager,
+                                                Dune::index_constant<i> domainI,
+                                                const GridGeometryI& gridGeometryI,
+                                                Dune::index_constant<j> domainJ,
+                                                const GridGeometryJ& gridGeometryJ)
+{
+    const auto numDofsI = gridGeometryI.numDofs();
+    const auto numDofsJ = gridGeometryJ.numDofs();
+    Dune::MatrixIndexSet pattern;
+    pattern.resize(numDofsI, numDofsJ);
+
+    // matrix pattern for implicit Jacobians
+    if (isImplicit)
+    {
+        static constexpr int dim = std::decay_t<decltype(gridGeometryI.gridView())>::dimension;
+        for (const auto& elementI : elements(gridGeometryI.gridView()))
+        {
+            const auto& stencil = couplingManager.couplingStencil(domainI, elementI, domainJ);
+            for (std::size_t vIdxLocal = 0; vIdxLocal < elementI.subEntities(dim); ++vIdxLocal)
+            {
+                const auto globalI = gridGeometryI.vertexMapper().subIndex(elementI, vIdxLocal, dim);
+                for (const auto globalJ : stencil)
+                    pattern.add(globalI, globalJ);
+            }
+        }
+    }
+
+    // matrix pattern for explicit Jacobians
+    // -> diagonal matrix, so coupling block is empty
+    // just return the empty pattern
+
+    return pattern;
+}
+
+/*!
+ * \ingroup Assembly
+ * \brief Helper function to generate coupling Jacobian pattern (off-diagonal blocks)
+ *        for the staggered scheme (degrees of freedom on cell centers)
+ */
+template<bool isImplicit, class CouplingManager, class GridGeometryI, class GridGeometryJ, std::size_t i, std::size_t j,
+         typename std::enable_if_t<(GridGeometryI::discMethod == DiscretizationMethod::staggered &&
+                                    GridGeometryI::isCellCenter()), int> = 0>
+Dune::MatrixIndexSet getCouplingJacobianPattern(const CouplingManager& couplingManager,
+                                                Dune::index_constant<i> domainI,
+                                                const GridGeometryI& gridGeometryI,
+                                                Dune::index_constant<j> domainJ,
+                                                const GridGeometryJ& gridGeometryJ)
+{
+    Dune::MatrixIndexSet pattern(gridGeometryI.numDofs(), gridGeometryJ.numDofs());
+
+    for (const auto& elementI : elements(gridGeometryI.gridView()))
+    {
+        const auto ccGlobalI = gridGeometryI.elementMapper().index(elementI);
+        for (auto&& faceGlobalJ : couplingManager.couplingStencil(domainI, elementI, domainJ))
+                pattern.add(ccGlobalI, faceGlobalJ);
+    }
+
+    return pattern;
+}
+
+/*!
+ * \ingroup Assembly
+ * \brief Helper function to generate coupling Jacobian pattern (off-diagonal blocks)
+ *        for the staggered scheme (degrees of freedom on faces)
+ */
+template<bool isImplicit, class CouplingManager, class GridGeometryI, class GridGeometryJ, std::size_t i, std::size_t j,
+         typename std::enable_if_t<(GridGeometryI::discMethod == DiscretizationMethod::staggered &&
+                                    GridGeometryI::isFace()), int> = 0>
+Dune::MatrixIndexSet getCouplingJacobianPattern(const CouplingManager& couplingManager,
+                                                Dune::index_constant<i> domainI,
+                                                const GridGeometryI& gridGeometryI,
+                                                Dune::index_constant<j> domainJ,
+                                                const GridGeometryJ& gridGeometryJ)
+{
+    Dune::MatrixIndexSet pattern(gridGeometryI.numDofs(), gridGeometryJ.numDofs());
+
+    for (const auto& elementI : elements(gridGeometryI.gridView()))
+    {
+        auto fvGeometry = localView(gridGeometryI);
+        fvGeometry.bindElement(elementI);
+
+        // loop over sub control faces
+        for (auto&& scvf : scvfs(fvGeometry))
+        {
+            const auto faceGlobalI = scvf.dofIndex();
+            for (auto&& globalJ : couplingManager.couplingStencil(domainI, scvf, domainJ))
+                pattern.add(faceGlobalI, globalJ);
+        }
+    }
+
+    return pattern;
+}
+
+} // namespace Dumux
+
+#endif
-- 
GitLab