diff --git a/dumux/assembly/CMakeLists.txt b/dumux/assembly/CMakeLists.txt index 65a7539064d99a5446047b668a8db18068f110f2..2543a6631f3a61445e1bbb4aeeb8461b93115bd7 100644 --- a/dumux/assembly/CMakeLists.txt +++ b/dumux/assembly/CMakeLists.txt @@ -8,6 +8,7 @@ entitycolor.hh fvassembler.hh fvlocalassemblerbase.hh fvlocalresidual.hh +initialsolution.hh jacobianpattern.hh numericepsilon.hh partialreassembler.hh diff --git a/dumux/assembly/initialsolution.hh b/dumux/assembly/initialsolution.hh new file mode 100644 index 0000000000000000000000000000000000000000..dc8bf7ebf3a04615577efcac8d7c40de4c726cd6 --- /dev/null +++ b/dumux/assembly/initialsolution.hh @@ -0,0 +1,111 @@ +// -*- 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 Assembly + * \brief Function to create initial solution vectors + */ +#ifndef DUMUX_ASSEMBLY_INITIAL_SOLUTION_HH +#define DUMUX_ASSEMBLY_INITIAL_SOLUTION_HH + +#include <vector> +#include <type_traits> + +#include <dumux/discretization/method.hh> + +namespace Dumux { + +/*! + * \file + * \ingroup Assembly + * \brief Set a solution vector to the initial solution provided by the problem + */ +template<class SolutionVector, class Problem> +void assembleInitialSolution(SolutionVector& sol, const Problem& problem) +{ + const auto& gg = problem.gridGeometry(); + using GridGeometry = std::decay_t<decltype(gg)>; + + // box method + if constexpr (GridGeometry::discMethod == DiscretizationMethod::box) + { + constexpr int dim = GridGeometry::GridView::dimension; + const auto numDofs = gg.vertexMapper().size(); + const auto numVert = gg.gridView().size(dim); + sol.resize(numDofs); + + // if there are more dofs than vertices (enriched nodal dofs), we have to + // call initial for all dofs at the nodes, coming from all neighboring elements. + if (numDofs != numVert) + { + std::vector<bool> dofVisited(numDofs, false); + for (const auto& element : elements(gg.gridView())) + { + for (int i = 0; i < element.subEntities(dim); ++i) + { + const auto dofIdxGlobal = gg.vertexMapper().subIndex(element, i, dim); + // forward to implementation if value at dof is not set yet + if (!dofVisited[dofIdxGlobal]) + { + sol[dofIdxGlobal] = problem.initial(element.template subEntity<dim>(i)); + dofVisited[dofIdxGlobal] = true; + } + } + } + } + + // otherwise we directly loop over the vertices + else + { + for (const auto& vertex : vertices(gg.gridView())) + sol[gg.vertexMapper().index(vertex)] = problem.initial(vertex); + } + } + + // staggered methods + else if constexpr (GridGeometry::discMethod == DiscretizationMethod::staggered) + { + problem.applyInitialSolution(sol); + } + + // default: cell-centered methods + else + { + sol.resize(gg.numDofs()); + for (const auto& element : elements(gg.gridView())) + sol[gg.elementMapper().index(element)] = problem.initial(element); + } +} + +/*! + * \file + * \ingroup Assembly + * \brief Create a solution vector filled with the initial solution provided by the problem + */ +template<class SolutionVector, class Problem> +SolutionVector makeInitialSolution(const Problem& problem) +{ + SolutionVector sol; + assembleInitialSolution(sol, problem); + return sol; +} + +} // end namespace Dumux + +#endif diff --git a/dumux/common/fvproblem.hh b/dumux/common/fvproblem.hh index 47e6f4313e90b308672d9147b2dce9bf18751da5..ea3f813b07a4344fbe54ccc2679ce58254859020 100644 --- a/dumux/common/fvproblem.hh +++ b/dumux/common/fvproblem.hh @@ -34,6 +34,8 @@ #include <dumux/common/parameters.hh> #include <dumux/discretization/method.hh> +#include <dumux/assembly/initialsolution.hh> + namespace Dumux { /*! @@ -65,13 +67,6 @@ class FVProblem using PointSourceMap = std::map< std::pair<std::size_t, std::size_t>, std::vector<PointSource> >; - using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; - using ElementFluxVariablesCache = typename GetPropType<TypeTag, Properties::GridFluxVariablesCache>::LocalView; - using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView; - using VolumeVariables = typename ElementVolumeVariables::VolumeVariables; - - using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>; - static constexpr bool isBox = GridGeometry::discMethod == DiscretizationMethod::box; static constexpr bool isStaggered = GridGeometry::discMethod == DiscretizationMethod::staggered; @@ -280,6 +275,7 @@ public: * Negative values mean influx. * E.g. for the mass balance that would be the mass flux in \f$ [ kg / (m^2 \cdot s)] \f$. */ + template<class ElementVolumeVariables, class ElementFluxVariablesCache> NumEqVector neumann(const Element& element, const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars, @@ -324,6 +320,7 @@ public: * that the conserved quantity is created, negative ones mean that it vanishes. * E.g. for the mass balance that would be a mass rate in \f$ [ kg / (m^3 \cdot s)] \f$. */ + template<class ElementVolumeVariables> NumEqVector source(const Element &element, const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars, @@ -387,6 +384,7 @@ public: * Positive values mean that the conserved quantity is created, negative ones mean that it vanishes. * E.g. for the mass balance that would be a mass rate in \f$ [ kg / s ] \f$. */ + template<class ElementVolumeVariables> void pointSource(PointSource& source, const Element &element, const FVElementGeometry& fvGeometry, @@ -419,7 +417,7 @@ public: * \brief Add source term derivative to the Jacobian * \note Only needed in case of analytic differentiation and solution dependent sources */ - template<class MatrixBlock> + template<class MatrixBlock, class VolumeVariables> void addSourceDerivatives(MatrixBlock& block, const Element& element, const FVElementGeometry& fvGeometry, @@ -432,6 +430,7 @@ public: * Caution: Only overload this method in the implementation if you know * what you are doing. */ + template<class ElementVolumeVariables> NumEqVector scvPointSources(const Element &element, const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars, @@ -508,10 +507,10 @@ public: * \brief Applies the initial solution for all degrees of freedom of the grid. * \param sol the initial solution vector */ + template<class SolutionVector> void applyInitialSolution(SolutionVector& sol) const { - // set the initial values by forwarding to a specialized method - applyInitialSolutionImpl_(sol, std::integral_constant<bool, isBox>()); + assembleInitialSolution(sol, asImp_()); } /*! @@ -596,60 +595,6 @@ protected: { return *static_cast<const Implementation *>(this); } private: - /*! - * \brief Applies the initial solution for the box method - */ - void applyInitialSolutionImpl_(SolutionVector& sol, /*isBox=*/std::true_type) const - { - const auto numDofs = gridGeometry_->vertexMapper().size(); - const auto numVert = gridGeometry_->gridView().size(dim); - sol.resize(numDofs); - - // if there are more dofs than vertices (enriched nodal dofs), we have to - // call initial for all dofs at the nodes, coming from all neighboring elements. - if (numDofs != numVert) - { - std::vector<bool> dofVisited(numDofs, false); - for (const auto& element : elements(gridGeometry_->gridView())) - { - for (int i = 0; i < element.subEntities(dim); ++i) - { - const auto dofIdxGlobal = gridGeometry_->vertexMapper().subIndex(element, i, dim); - - // forward to implementation if value at dof is not set yet - if (!dofVisited[dofIdxGlobal]) - { - sol[dofIdxGlobal] = asImp_().initial(element.template subEntity<dim>(i)); - dofVisited[dofIdxGlobal] = true; - } - } - } - } - - // otherwise we directly loop over the vertices - else - { - for (const auto& vertex : vertices(gridGeometry_->gridView())) - { - const auto dofIdxGlobal = gridGeometry_->vertexMapper().index(vertex); - sol[dofIdxGlobal] = asImp_().initial(vertex); - } - } - } - - /*! - * \brief Applies the initial solution for cell-centered methods - */ - void applyInitialSolutionImpl_(SolutionVector& sol, /*isBox=*/std::false_type) const - { - sol.resize(gridGeometry_->numDofs()); - for (const auto& element : elements(gridGeometry_->gridView())) - { - const auto dofIdxGlobal = gridGeometry_->elementMapper().index(element); - sol[dofIdxGlobal] = asImp_().initial(element); - } - } - //! The finite volume grid geometry std::shared_ptr<const GridGeometry> gridGeometry_;