diff --git a/dumux/discretization/cellcentered/mpfa/CMakeLists.txt b/dumux/discretization/cellcentered/mpfa/CMakeLists.txt index 07756ca4fd6ed7951b0f48a2645d219e78f1b9c0..5e4c4794d76ea53cbc355227c7fe81eb15aaa976 100644 --- a/dumux/discretization/cellcentered/mpfa/CMakeLists.txt +++ b/dumux/discretization/cellcentered/mpfa/CMakeLists.txt @@ -17,6 +17,7 @@ helper.hh interactionvolumebase.hh interactionvolumedatahandle.hh localassemblerbase.hh +localassemblerhelper.hh localfacedata.hh methods.hh scvgradients.hh diff --git a/dumux/discretization/cellcentered/mpfa/localassemblerbase.hh b/dumux/discretization/cellcentered/mpfa/localassemblerbase.hh index 381466e123dcd109dad5d5374b7e159e580d4b08..b8ce045537b31d3a654e7fc1ce38050b51722abf 100644 --- a/dumux/discretization/cellcentered/mpfa/localassemblerbase.hh +++ b/dumux/discretization/cellcentered/mpfa/localassemblerbase.hh @@ -26,23 +26,21 @@ #ifndef DUMUX_DISCRETIZATION_CC_MPFA_LOCAL_ASSEMBLER_BASE_HH #define DUMUX_DISCRETIZATION_CC_MPFA_LOCAL_ASSEMBLER_BASE_HH -#include <utility> -#include <type_traits> - #include <dune/common/exceptions.hh> #include <dune/common/reservedvector.hh> #include <dumux/common/typetraits/isvalid.hh> +#include "localassemblerhelper.hh" + +namespace Dumux { -namespace Dumux -{ /*! * \ingroup CCMpfaDiscretization * \brief Defines the general interface of the local assembler * classes for the assembly of the interaction volume-local * transmissibility matrix. Specializations have to be provided * for the available interaction volume implementations. these - * should derive from this base clases. + * should derive from this base class. * * \tparam P The problem type * \tparam EG The element finite volume geometry @@ -50,34 +48,13 @@ namespace Dumux */ template< class P, class EG, class EV > class InteractionVolumeAssemblerBase +: public InteractionVolumeAssemblerHelper { using Problem = P; using FVElementGeometry = EG; using ElementVolumeVariables = EV; - // Helper structs to detect if matrix has resize function - struct HasMatrixResize - { - template<class M> - auto operator()(const M& m) -> decltype(std::declval<M>().resize(0, 0)) - {} - }; - - // Helper structs to detect if vector has resize function - struct HasVectorResize - { - template<class V> - auto operator()(const V& v) -> decltype(std::declval<V>().resize(0)) - {} - }; - - template<class Matrix> - static constexpr auto matrixHasResizeFunction() - { return decltype( isValid(HasMatrixResize())(std::declval<Matrix>()) )::value; } - - template<class Vector> - static constexpr auto vectorHasResizeFunction() - { return decltype( isValid(HasVectorResize())(std::declval<Vector>()) )::value; } + using Helper = InteractionVolumeAssemblerHelper; public: /*! @@ -138,72 +115,6 @@ class InteractionVolumeAssemblerBase DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assemble() function for the cell/Dirichlet unknowns"); } - /*! - * \brief Assembles the vector of face unknowns within an interaction volume. - * \note This requires the data handle to be fully assembled already. - * - * \param handle The data handle in which the vector is stored - * \param iv The interaction volume - */ - template< class DataHandle, class IV > - static typename IV::Traits::MatVecTraits::FaceVector - assembleFaceUnkowns(const DataHandle& handle, const IV& iv) - { - typename IV::Traits::MatVecTraits::FaceVector u; - resizeVector_(u, iv.numFaces()); - - handle.AB().mv(handle.uj(), u); - - // maybe add gravity terms - if (handle.deltaG().size() == iv.numUnknowns()) - handle.AB().umv(handle.deltaG(), u); - - return u; - } - - /*! - * \brief Assembles the solution gradients in the - * sub-control volumes within an interaction volume. - * \note This requires the data handle to be fully assembled already. - * - * \param handle The data handle in which the vector is stored - * \param iv The interaction volume - */ - template< class DataHandle, class IV > - static std::vector< typename IV::Traits::LocalScvType::GlobalCoordinate > - assembleScvGradients(const DataHandle& handle, const IV& iv) - { - const auto u = assembleFaceUnkowns(handle, iv); - - using LocalScv = typename IV::Traits::LocalScvType; - using Gradient = typename LocalScv::GlobalCoordinate; - - std::vector<Gradient> result; result.reserve(iv.numScvs()); - for (unsigned int scvIdx = 0; scvIdx < iv.numScvs(); ++scvIdx) - { - const auto& scv = iv.localScv(scvIdx); - - Gradient gradU(0.0); - for (unsigned int dir = 0; dir < LocalScv::myDimension; ++dir) - { - auto nu = scv.nu(dir); - - // obtain face pressure - const auto& scvf = iv.localScvf( scv.localScvfIndex(dir) ); - const auto faceU = !scvf.isDirichlet() ? u[scvf.localDofIndex()] - : handle.uj()[scvf.localDofIndex()]; - - nu *= faceU - handle.uj()[scv.localDofIndex()]; - gradU += nu; - } - - gradU /= scv.detX(); - result.emplace_back( std::move(gradU) ); - } - - return result; - } - /*! * \brief Assembles the gravitational flux contributions on the scvfs within an * interaction volume. @@ -224,10 +135,10 @@ class InteractionVolumeAssemblerBase auto& g = handle.g(); auto& deltaG = handle.deltaG(); auto& outsideG = handle.gOutside(); - resizeVector_(g, iv.numFaces()); - resizeVector_(deltaG, iv.numUnknowns()); + Helper::resizeVector(g, iv.numFaces()); + Helper::resizeVector(deltaG, iv.numUnknowns()); if (isSurfaceGrid) - resizeVector_(outsideG, iv.numFaces()); + Helper::resizeVector(outsideG, iv.numFaces()); //! For each face, we... //! - arithmetically average the phase densities @@ -260,7 +171,7 @@ class InteractionVolumeAssemblerBase Scalar rho; if (isSurfaceGrid) - resizeVector_(outsideG[faceIdx], numOutsideFaces); + Helper::resizeVector(outsideG[faceIdx], numOutsideFaces); if (!curLocalScvf.isDirichlet()) { @@ -316,7 +227,7 @@ class InteractionVolumeAssemblerBase { using FaceVector = typename IV::Traits::MatVecTraits::FaceVector; FaceVector AG; - resizeVector_(AG, iv.numUnknowns()); + Helper::resizeVector(AG, iv.numUnknowns()); handle.A().mv(deltaG, AG); // compute gravitational accelerations @@ -344,39 +255,6 @@ class InteractionVolumeAssemblerBase } } -protected: - //! resizes a matrix to the given sizes (specialization for dynamic matrix type) - template< class Matrix, - class size_type, - std::enable_if_t<matrixHasResizeFunction<Matrix>(), int> = 0 > - static void resizeMatrix_(Matrix& M, size_type rows, size_type cols) - { - M.resize(rows, cols); - } - - //! resizes a matrix to the given sizes (specialization for static matrix type - do nothing) - template< class Matrix, - class size_type, - std::enable_if_t<!matrixHasResizeFunction<Matrix>(), int> = 0 > - static void resizeMatrix_(Matrix& M, size_type rows, size_type cols) - {} - - //! resizes a vector to the given size (specialization for dynamic matrix type) - template< class Vector, - class size_type, - std::enable_if_t<vectorHasResizeFunction<Vector>(), int> = 0 > - static void resizeVector_(Vector& v, size_type size) - { - v.resize(size); - } - - //! resizes a vector to the given size (specialization for static vector type - do nothing) - template< class Vector, - class size_type, - std::enable_if_t<!vectorHasResizeFunction<Vector>(), int> = 0 > - static void resizeVector_(Vector& v, size_type rows) - {} - private: // pointers to the data required for assembly const Problem* problemPtr_; diff --git a/dumux/discretization/cellcentered/mpfa/localassemblerhelper.hh b/dumux/discretization/cellcentered/mpfa/localassemblerhelper.hh new file mode 100644 index 0000000000000000000000000000000000000000..0ce355049ea036114188f1cb15d9b4f370cdbfdb --- /dev/null +++ b/dumux/discretization/cellcentered/mpfa/localassemblerhelper.hh @@ -0,0 +1,171 @@ +// -*- 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 CCMpfaDiscretization + * \brief A class that contains helper functions as well as functionality + * which is common to different mpfa schemes and which solely + * operate on the interaction volume. + */ +#ifndef DUMUX_DISCRETIZATION_CC_MPFA_LOCAL_ASSEMBLER_HELPER_HH +#define DUMUX_DISCRETIZATION_CC_MPFA_LOCAL_ASSEMBLER_HELPER_HH + +#include <vector> +#include <utility> +#include <type_traits> + +#include <dumux/common/typetraits/isvalid.hh> + +namespace Dumux { + +/*! + * \ingroup CCMpfaDiscretization + * \brief A class that contains helper functions as well as functionality + * which is common to different mpfa schemes and which solely + * operate on the interaction volume. + */ +class InteractionVolumeAssemblerHelper +{ + // Helper structs to detect if matrix has resize function + struct HasMatrixResize + { + template<class M> + auto operator()(const M& m) -> decltype(std::declval<M>().resize(0, 0)) + {} + }; + + // Helper structs to detect if vector has resize function + struct HasVectorResize + { + template<class V> + auto operator()(const V& v) -> decltype(std::declval<V>().resize(0)) + {} + }; + + template<class Matrix> + static constexpr auto matrixHasResizeFunction() + { return decltype( isValid(HasMatrixResize())(std::declval<Matrix>()) )::value; } + + template<class Vector> + static constexpr auto vectorHasResizeFunction() + { return decltype( isValid(HasVectorResize())(std::declval<Vector>()) )::value; } + +public: + /*! + * \brief Assembles the vector of face unknowns within an interaction volume. + * \note This requires the data handle to be fully assembled already. + * + * \param handle The data handle in which the vector is stored + * \param iv The interaction volume + */ + template< class DataHandle, class IV > + static typename IV::Traits::MatVecTraits::FaceVector + assembleFaceUnkowns(const DataHandle& handle, const IV& iv) + { + typename IV::Traits::MatVecTraits::FaceVector u; + resizeVector(u, iv.numFaces()); + + handle.AB().mv(handle.uj(), u); + + // maybe add gravity terms + if (handle.deltaG().size() == iv.numUnknowns()) + handle.AB().umv(handle.deltaG(), u); + + return u; + } + + /*! + * \brief Assembles the solution gradients in the + * sub-control volumes within an interaction volume. + * \note This requires the data handle to be fully assembled already. + * + * \param handle The data handle in which the vector is stored + * \param iv The interaction volume + */ + template< class DataHandle, class IV > + static std::vector< typename IV::Traits::LocalScvType::GlobalCoordinate > + assembleScvGradients(const DataHandle& handle, const IV& iv) + { + const auto u = assembleFaceUnkowns(handle, iv); + + using LocalScv = typename IV::Traits::LocalScvType; + using Gradient = typename LocalScv::GlobalCoordinate; + + std::vector<Gradient> result; result.reserve(iv.numScvs()); + for (unsigned int scvIdx = 0; scvIdx < iv.numScvs(); ++scvIdx) + { + const auto& scv = iv.localScv(scvIdx); + + Gradient gradU(0.0); + for (unsigned int dir = 0; dir < LocalScv::myDimension; ++dir) + { + auto nu = scv.nu(dir); + + // obtain face pressure + const auto& scvf = iv.localScvf( scv.localScvfIndex(dir) ); + const auto faceU = !scvf.isDirichlet() ? u[scvf.localDofIndex()] + : handle.uj()[scvf.localDofIndex()]; + + nu *= faceU - handle.uj()[scv.localDofIndex()]; + gradU += nu; + } + + gradU /= scv.detX(); + result.emplace_back( std::move(gradU) ); + } + + return result; + } + + //! resizes a matrix to the given sizes (specialization for dynamic matrix type) + template< class Matrix, + class size_type, + std::enable_if_t<matrixHasResizeFunction<Matrix>(), int> = 0 > + static void resizeMatrix(Matrix& M, size_type rows, size_type cols) + { + M.resize(rows, cols); + } + + //! resizes a matrix to the given sizes (specialization for static matrix type - do nothing) + template< class Matrix, + class size_type, + std::enable_if_t<!matrixHasResizeFunction<Matrix>(), int> = 0 > + static void resizeMatrix(Matrix& M, size_type rows, size_type cols) + {} + + //! resizes a vector to the given size (specialization for dynamic matrix type) + template< class Vector, + class size_type, + std::enable_if_t<vectorHasResizeFunction<Vector>(), int> = 0 > + static void resizeVector(Vector& v, size_type size) + { + v.resize(size); + } + + //! resizes a vector to the given size (specialization for static vector type - do nothing) + template< class Vector, + class size_type, + std::enable_if_t<!vectorHasResizeFunction<Vector>(), int> = 0 > + static void resizeVector(Vector& v, size_type rows) + {} +}; + +} // end namespace Dumux + +#endif diff --git a/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh b/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh index a4039645784954e00004fc1caf71c3dc756fedc6..0843c7f6f2f9320fda38f38122a418cf89bc7f4a 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh @@ -30,6 +30,7 @@ #include <dumux/common/math.hh> #include <dumux/discretization/cellcentered/mpfa/methods.hh> #include <dumux/discretization/cellcentered/mpfa/localassemblerbase.hh> +#include <dumux/discretization/cellcentered/mpfa/localassemblerhelper.hh> #include <dumux/discretization/cellcentered/mpfa/computetransmissibility.hh> namespace Dumux @@ -49,6 +50,7 @@ class MpfaOInteractionVolumeAssembler : public InteractionVolumeAssemblerBase< P, EG, EV > { using ParentType = InteractionVolumeAssemblerBase< P, EG, EV >; + using Helper = InteractionVolumeAssemblerHelper; public: //! Pull up constructor of the base class @@ -99,7 +101,7 @@ public: tijOut[fIdx].resize(numOutsideFaces); std::for_each(tijOut[fIdx].begin(), tijOut[fIdx].end(), - [&](auto& v) { this->resizeVector_(v, iv.numKnowns()); }); + [&](auto& v) { Helper::resizeVector(v, iv.numKnowns()); }); } // compute outside transmissibilities @@ -155,7 +157,7 @@ public: void assembleU(DataHandle& handle, const IV& iv, const GetU& getU) { auto& u = handle.uj(); - this->resizeVector_(u, iv.numKnowns()); + Helper::resizeVector(u, iv.numKnowns()); // put the cell unknowns first, then Dirichlet values typename IV::Traits::IndexSet::LocalIndexType i = 0; @@ -202,14 +204,14 @@ private: static constexpr int dimWorld = IV::Traits::GridView::dimensionworld; // resize omegas - this->resizeVector_(wijk, iv.numFaces()); + Helper::resizeVector(wijk, iv.numFaces()); // if only Dirichlet faces are present in the iv, // the matrices A, B & C are undefined and D = T if (iv.numUnknowns() == 0) { // resize & reset D matrix - this->resizeMatrix_(D, iv.numFaces(), iv.numKnowns()); D = 0.0; + Helper::resizeMatrix(D, iv.numFaces(), iv.numKnowns()); D = 0.0; // Loop over all the faces, in this case these are all dirichlet boundaries for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx) @@ -226,7 +228,7 @@ private: const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); // the omega factors of the "positive" sub volume - this->resizeVector_(wijk[faceIdx], /*no outside scvs present*/1); + Helper::resizeVector(wijk[faceIdx], /*no outside scvs present*/1); wijk[faceIdx][0] = computeMpfaTransmissibility(posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor()); const auto posScvLocalDofIdx = posLocalScv.localDofIndex(); @@ -242,10 +244,10 @@ private: else { // resize & reset matrices - this->resizeMatrix_(A, iv.numUnknowns(), iv.numUnknowns()); A = 0.0; - this->resizeMatrix_(B, iv.numUnknowns(), iv.numKnowns()); B = 0.0; - this->resizeMatrix_(C, iv.numFaces(), iv.numUnknowns()); C = 0.0; - this->resizeMatrix_(D, iv.numFaces(), iv.numKnowns()); D = 0.0; + Helper::resizeMatrix(A, iv.numUnknowns(), iv.numUnknowns()); A = 0.0; + Helper::resizeMatrix(B, iv.numUnknowns(), iv.numKnowns()); B = 0.0; + Helper::resizeMatrix(C, iv.numFaces(), iv.numUnknowns()); C = 0.0; + Helper::resizeMatrix(D, iv.numFaces(), iv.numKnowns()); D = 0.0; for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx) { @@ -263,7 +265,7 @@ private: const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); // the omega factors of the "positive" sub volume - this->resizeVector_(wijk[faceIdx], neighborScvIndices.size()); + Helper::resizeVector(wijk[faceIdx], neighborScvIndices.size()); wijk[faceIdx][0] = computeMpfaTransmissibility(posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor()); // go over the coordinate directions in the positive sub volume