diff --git a/dumux/multidomain/common/multidomainassembler.hh b/dumux/multidomain/common/multidomainassembler.hh new file mode 100644 index 0000000000000000000000000000000000000000..32f7bec7a8091bb665548e3116039b2d7e91b89e --- /dev/null +++ b/dumux/multidomain/common/multidomainassembler.hh @@ -0,0 +1,248 @@ +// -*- 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/>. * + *****************************************************************************/ +#ifndef DUMUX_MULTIDOMAIN_ASSEMBLER_HH +#define DUMUX_MULTIDOMAIN_ASSEMBLER_HH + +#include "multidomainproperties.hh" +#include "multidomainpropertydefaults.hh" +#include <dune/pdelab/constraints/constraintsparameters.hh> +#include <dune/pdelab/multidomain/constraints.hh> + +namespace Dumux { + +//! Prevents the setting of a dirichlet constraint anywhere +struct NoDirichletConstraints : + public Dune::PDELab::DirichletConstraintsParameters +{ + template<typename I> + bool isDirichlet(const I& intersection, const Dune::FieldVector<typename I::ctype, I::dimension-1> & coord) const + { + return false; + } +}; + +template<class TypeTag> +class MultiDomainAssembler +{ + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, MDGrid) MDGrid; + + typedef typename GET_PROP_TYPE(TypeTag, SubProblem1TypeTag) SubTypeTag1; + typedef typename GET_PROP_TYPE(TypeTag, SubProblem2TypeTag) SubTypeTag2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, Problem) SubProblem1; + typedef typename GET_PROP_TYPE(SubTypeTag2, Problem) SubProblem2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, LocalFEMSpace) FEM1; + typedef typename GET_PROP_TYPE(SubTypeTag2, LocalFEMSpace) FEM2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, ScalarGridFunctionSpace) ScalarGridFunctionSpace1; + typedef typename GET_PROP_TYPE(SubTypeTag2, ScalarGridFunctionSpace) ScalarGridFunctionSpace2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, GridFunctionSpace) GridFunctionSpace1; + typedef typename GET_PROP_TYPE(SubTypeTag2, GridFunctionSpace) GridFunctionSpace2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, LocalOperator) LocalOperator1; + typedef typename GET_PROP_TYPE(SubTypeTag2, LocalOperator) LocalOperator2; + + typedef typename GET_PROP_TYPE(TypeTag, MDGridFunctionSpace) MDGridFunctionSpace; + typedef typename GET_PROP_TYPE(TypeTag, MDCondition) MDCondition; + typedef typename GET_PROP_TYPE(TypeTag, MDSubProblem1) MDSubProblem1; + typedef typename GET_PROP_TYPE(TypeTag, MDSubProblem2) MDSubProblem2; + typedef typename GET_PROP_TYPE(TypeTag, MDCouplingLocalOperator) MDCouplingLocalOperator; + typedef typename GET_PROP_TYPE(TypeTag, MDCoupling) MDCoupling; + typedef typename GET_PROP_TYPE(TypeTag, MDConstraintsTrafo) MDConstraintsTrafo; + typedef typename GET_PROP_TYPE(TypeTag, MDGridOperator) MDGridOperator; + + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; + + typedef typename GET_PROP_TYPE(SubTypeTag1, Constraints) Constraints1; + typedef typename GET_PROP_TYPE(SubTypeTag2, Constraints) Constraints2; + + // copying the jacobian assembler is not a good idea + MultiDomainAssembler(const MultiDomainAssembler &); + +public: + MultiDomainAssembler() + { + globalProblem_ = 0; + problem1_= 0; + problem2_= 0; + } + + ~MultiDomainAssembler() + { } + + /*! + * \brief docme + * + * \param problem docme + * + */ + void init(Problem& problem) + { + globalProblem_ = &problem; + problem1_ = &globalProblem_->subProblem1(); + problem2_ = &globalProblem_->subProblem2(); + + fem1_ = Dune::make_shared<FEM1>(); + fem2_ = Dune::make_shared<FEM2>(); + + constraints1_ = Dune::make_shared<Constraints1>(); + constraints2_ = Dune::make_shared<Constraints2>(); + + scalarGridFunctionSpace1_ = Dune::make_shared<ScalarGridFunctionSpace1>(problem1_->gridView(), + *fem1_, + *constraints1_); + scalarGridFunctionSpace2_ = Dune::make_shared<ScalarGridFunctionSpace2>(problem2_->gridView(), + *fem2_, + *constraints2_); + // constraints store indices of ghost dofs + constraints1_->compute_ghosts(*scalarGridFunctionSpace1_); + constraints2_->compute_ghosts(*scalarGridFunctionSpace2_); + Valgrind::CheckDefined(*constraints1_); + Valgrind::CheckDefined(*constraints2_); +// std::cerr << __FILE__ << ":" << __LINE__ << "\n"; + + gridFunctionSpace1_ = Dune::make_shared<GridFunctionSpace1>(*scalarGridFunctionSpace1_); + gridFunctionSpace2_ = Dune::make_shared<GridFunctionSpace2>(*scalarGridFunctionSpace2_); + + mdGridFunctionSpace_ = Dune::make_shared<MDGridFunctionSpace>(globalProblem_->mdGrid(), + *gridFunctionSpace1_, + *gridFunctionSpace2_); + + localOperator1_ = Dune::make_shared<LocalOperator1>(problem1_->model()); + localOperator2_ = Dune::make_shared<LocalOperator2>(problem2_->model()); + + condition1_ = Dune::make_shared<MDCondition>(0); + condition2_ = Dune::make_shared<MDCondition>(1); + + mdSubProblem1_ = Dune::make_shared<MDSubProblem1>(*localOperator1_, *condition1_); + mdSubProblem2_ = Dune::make_shared<MDSubProblem2>(*localOperator2_, *condition2_); + + couplingLocalOperator_ = Dune::make_shared<MDCouplingLocalOperator>(*globalProblem_); + mdCoupling_ = Dune::make_shared<MDCoupling>(*mdSubProblem1_, *mdSubProblem2_, *couplingLocalOperator_); + + // TODO proper constraints stuff + constraintsTrafo_ = Dune::make_shared<MDConstraintsTrafo>(); + + NoDirichletConstraints dirichletVal; + auto constraints = Dune::PDELab::MultiDomain::constraints<Scalar>(*mdGridFunctionSpace_, + Dune::PDELab::MultiDomain::constrainSubProblem(*mdSubProblem1_,dirichletVal), + Dune::PDELab::MultiDomain::constrainSubProblem(*mdSubProblem2_,dirichletVal)); + constraints.assemble(*constraintsTrafo_); + + mdGridOperator_ = Dune::make_shared<MDGridOperator>(*mdGridFunctionSpace_, *mdGridFunctionSpace_, + *constraintsTrafo_, *constraintsTrafo_, + *mdSubProblem1_, *mdSubProblem2_, *mdCoupling_); + + matrix_ = Dune::make_shared<JacobianMatrix>(*mdGridOperator_); + *matrix_ = 0; + + residual_.resize(matrix_->N()); + } + + /*! + * \brief docme + */ + void assemble() + { +// std::cerr << __FILE__ << ":" << __LINE__ << "\n"; + + // assemble the matrix + *matrix_ = 0; + + residual_ = 0; + mdGridOperator_->jacobian(globalProblem_->model().curSol(), *matrix_); +// printmatrix(std::cout, matrix_->base(), "global stiffness matrix", "row", 11, 3); + + // calculate the global residual + residual_ = 0; + mdGridOperator_->residual(globalProblem_->model().curSol(), residual_); +// printvector(std::cout, residual_, "residual", "row", 200, 1, 3); + } + + //! return const reference to matrix + const JacobianMatrix &matrix() const + { return *matrix_; } + //! return reference to matrix + // This is not very nice, but required for the AMG solver + JacobianMatrix &matrix() + { return *matrix_; } + + //! return const reference to residual + const SolutionVector &residual() const + { return residual_; } + SolutionVector &residual() + { return residual_; } + + //! return the multidomain gridfunctionspace + MDGridFunctionSpace &gridFunctionSpace() const + { return *mdGridFunctionSpace_; } + MDGridFunctionSpace &mdGridFunctionSpace() const + { return *mdGridFunctionSpace_; } + + //! return the multidomain constraints trafo + MDConstraintsTrafo &constraintsTrafo() const + { return *constraintsTrafo_; } + +private: + Problem *globalProblem_; + SubProblem1 *problem1_; + SubProblem2 *problem2_; + + Dune::shared_ptr<FEM1> fem1_; + Dune::shared_ptr<FEM2> fem2_; + + Dune::shared_ptr<Constraints1> constraints1_; + Dune::shared_ptr<Constraints2> constraints2_; + + Dune::shared_ptr<ScalarGridFunctionSpace1> scalarGridFunctionSpace1_; + Dune::shared_ptr<ScalarGridFunctionSpace2> scalarGridFunctionSpace2_; + + Dune::shared_ptr<GridFunctionSpace1> gridFunctionSpace1_; + Dune::shared_ptr<GridFunctionSpace2> gridFunctionSpace2_; + Dune::shared_ptr<MDGridFunctionSpace> mdGridFunctionSpace_; + + Dune::shared_ptr<LocalOperator1> localOperator1_; + Dune::shared_ptr<LocalOperator2> localOperator2_; + + Dune::shared_ptr<MDCondition> condition1_; + Dune::shared_ptr<MDCondition> condition2_; + + Dune::shared_ptr<MDSubProblem1> mdSubProblem1_; + Dune::shared_ptr<MDSubProblem2> mdSubProblem2_; + + Dune::shared_ptr<MDCouplingLocalOperator> couplingLocalOperator_; + Dune::shared_ptr<MDCoupling> mdCoupling_; + + Dune::shared_ptr<MDConstraintsTrafo> constraintsTrafo_; + Dune::shared_ptr<MDGridOperator> mdGridOperator_; + + Dune::shared_ptr<JacobianMatrix> matrix_; + + SolutionVector residual_; +}; + +} // namespace Dumux + +#endif + diff --git a/dumux/multidomain/common/multidomainconvergencewriter.hh b/dumux/multidomain/common/multidomainconvergencewriter.hh new file mode 100644 index 0000000000000000000000000000000000000000..75cf4673563e786edcc590530bed011b15a79ba9 --- /dev/null +++ b/dumux/multidomain/common/multidomainconvergencewriter.hh @@ -0,0 +1,163 @@ +// -*- 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 newton convergence writer for coupled problems. +*/ +#ifndef DUMUX_COUPLED_NEWTON_CONVERGENCEWRITER_HH +#define DUMUX_COUPLED_NEWTON_CONVERGENCEWRITER_HH + +#include <dune/pdelab/backend/istlsolverbackend.hh> +#include <dumux/io/vtkmultiwriter.hh> +#include <dune/grid/multidomaingrid.hh> + +#include "coupledcommon.hh" +#include "couplednewtoncontroller.hh" + +/*! + * \file + * \brief Forward declaration of properties required for the coupled Newton convergence writer + */ +namespace Dumux +{ +namespace Properties +{ + // forward declaration + NEW_PROP_TAG(SubProblem1TypeTag); + NEW_PROP_TAG(SubProblem2TypeTag); + NEW_PROP_TAG(Grid); + NEW_PROP_TAG(GridView); +} + + +//! \cond INTERNAL +/*! + * \brief Writes the intermediate solutions during + * the Newton scheme + */ +template <class TypeTag> +struct CoupledNewtonConvergenceWriter +{ + //typedef typename GET_PROP_TYPE(TypeTag, Grid) HostGrid; + //typedef Dune::mdgrid::FewSubDomainsTraits<HostGrid::dimension,4> MDGridTraits; + //typedef Dune::MultiDomainGrid<HostGrid, MDGridTraits> MDGrid; + //typedef typename MDGrid::LeafGridView MDGridView; + + typedef typename GET_PROP_TYPE(TypeTag, NewtonController) NewtonController; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + + typedef typename GET_PROP_TYPE(TypeTag, SubProblem1TypeTag) SubProblem1TypeTag; + typedef typename GET_PROP_TYPE(TypeTag, SubProblem2TypeTag) SubProblem2TypeTag; + + typedef typename GET_PROP_TYPE(SubProblem1TypeTag, GridView) GridView1; + typedef typename GET_PROP_TYPE(SubProblem2TypeTag, GridView) GridView2; + + typedef typename GET_PROP_TYPE(SubProblem1TypeTag, SolutionVector) SolutionVector1; + typedef typename GET_PROP_TYPE(SubProblem2TypeTag, SolutionVector) SolutionVector2; + + typedef Dumux::VtkMultiWriter<GridView1> VtkMultiWriter1; + typedef Dumux::VtkMultiWriter<GridView2> VtkMultiWriter2; + + CoupledNewtonConvergenceWriter(NewtonController &ctl) + : ctl_(ctl) + { + timeStepIndex_ = 0; + iteration_ = 0; + vtkMultiWriter1_ = 0; + vtkMultiWriter2_ = 0; + } + + ~CoupledNewtonConvergenceWriter() + { + delete vtkMultiWriter1_; + delete vtkMultiWriter2_; + }; + + void beginTimestep() + { + ++timeStepIndex_; + iteration_ = 0; + if (!vtkMultiWriter1_) + vtkMultiWriter1_ = new VtkMultiWriter1(problem_().subProblem1().gridView(), "convergence1"); + + if (!vtkMultiWriter2_) + vtkMultiWriter2_ = new VtkMultiWriter2(problem_().subProblem2().gridView(), "convergence2"); + }; + + void beginIteration(const GridView1 &gridView1, + const GridView2 &gridView2) + { + ++ iteration_; + vtkMultiWriter1_->beginWrite(timeStepIndex_ + iteration_ / 100.0); + vtkMultiWriter2_->beginWrite(timeStepIndex_ + iteration_ / 100.0); + }; + + void writeFields(const SolutionVector &uLastIter, + const SolutionVector &deltaU) + { + SolutionVector1 uLastIter1; + SolutionVector2 uLastIter2; + SolutionVector1 deltaU1; + SolutionVector2 deltaU2; + + uLastIter1.resize(ctl_.method().model().subModel1().numDofs()); + uLastIter2.resize(ctl_.method().model().subModel2().numDofs()); + deltaU1.resize(ctl_.method().model().subModel1().numDofs()); + deltaU2.resize(ctl_.method().model().subModel2().numDofs()); + + typedef Dumux::CoupledCommon<TypeTag> Common; + + Common::splitSolVector(uLastIter, uLastIter1, uLastIter2); + Common::splitSolVector(deltaU, deltaU1, deltaU2); + + + std::cout << "\n writing convergence file of current Newton iteration \n"; + ctl_.method().model().subModel1().addConvergenceVtkFields(*vtkMultiWriter1_, uLastIter1, deltaU1); + ctl_.method().model().subModel2().addConvergenceVtkFields(*vtkMultiWriter2_, uLastIter2, deltaU2); + }; + + void endIteration() + { + vtkMultiWriter1_->endWrite(); + vtkMultiWriter2_->endWrite(); + }; + + void endTimestep() + { + ++timeStepIndex_; + iteration_ = 0; + }; + +private: + const Problem &problem_() const + { return ctl_.method().problem(); } + + int timeStepIndex_; + int iteration_; + VtkMultiWriter1 *vtkMultiWriter1_; + VtkMultiWriter2 *vtkMultiWriter2_; + NewtonController &ctl_; +}; + +} // namespace Dumux + + +#endif diff --git a/dumux/multidomain/common/multidomainlocaloperator.hh b/dumux/multidomain/common/multidomainlocaloperator.hh new file mode 100644 index 0000000000000000000000000000000000000000..3662e08082d62ba5b361b25f4133c3ea31b163fb --- /dev/null +++ b/dumux/multidomain/common/multidomainlocaloperator.hh @@ -0,0 +1,119 @@ +// -*- 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/>. * + *****************************************************************************/ +#ifndef DUMUX_MULTIDOMAIN_BOX_LOCAL_OPERATOR_HH +#define DUMUX_MULTIDOMAIN_BOX_LOCAL_OPERATOR_HH + +#include<dune/pdelab/localoperator/pattern.hh> +#include<dune/pdelab/localoperator/flags.hh> + +#include <dumux/implicit/box/boxproperties.hh> + +namespace Dumux { + +namespace PDELab { + +template<class TypeTag> +class MultiDomainBoxLocalOperator +: +public Dune::PDELab::FullVolumePattern, +public Dune::PDELab::LocalOperatorDefaultFlags +{ + // copying the local operator for PDELab is not a good idea + MultiDomainBoxLocalOperator(const MultiDomainBoxLocalOperator &); + + typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename Grid::Traits::template Codim<0>::EntityPointer EntityPointer; + + enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; + +public: + // pattern assembly flags + enum { doPatternVolume = true }; + + // residual assembly flags + enum { doAlphaVolume = true }; + + MultiDomainBoxLocalOperator(Model &model) + : model_(model) + {} + + /*! + * \brief Volume integral depending on test and ansatz functions + * + * \param eg docme + * \param lfsu docme + * \param x docme + * \param lfsv docme + * \param r docme + * + */ + template<typename EG, typename LFSU, typename X, typename LFSV, typename R> + void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, + const LFSV& lfsv, R& r) const + { + typedef typename LFSU::Traits::SizeType size_type; + + const EntityPointer elementPtr = model_.gridView().grid().subDomainEntityPointer(eg.entity()); + model_.localResidual().eval(*elementPtr); + + int numVertices = x.size()/numEq; + for (size_type comp = 0; comp < r.size(); comp++) + r.accumulate(lfsv, comp, model_.localResidual().residual(comp%numVertices)[comp/numVertices]); + } + + /*! + * \brief Jacobian of volume term + * + * \param eg docme + * \param lfsu docme, is basis + * \param x docme + * \param lfsv docme, is test + * \param mat docme + * + */ + template<typename EG, typename LFSU, typename X, typename LFSV, typename M> + void jacobian_volume (const EG& eg, + const LFSU& lfsu, + const X& x, + const LFSV& lfsv, + M& mat) const + { + typedef typename LFSU::Traits::SizeType size_typeU; + typedef typename LFSV::Traits::SizeType size_typeV; + + const EntityPointer elementPtr = model_.gridView().grid().subDomainEntityPointer(eg.entity()); + model_.localJacobian().assemble(*elementPtr); + + int numVertices = x.size()/numEq; + for (size_typeV j=0; j<lfsv.size(); j++) { + for (size_typeU i=0; i<lfsu.size(); i++) { + mat.accumulate(lfsv, i, lfsu, j, (model_.localJacobian().mat(i%numVertices,j%numVertices))[i/numVertices][j/numVertices]); + } + } + } + +private: + Model& model_; +}; + +} // namespace PDELab +} // namespace Dumux + +#endif diff --git a/dumux/multidomain/common/multidomainmodel.hh b/dumux/multidomain/common/multidomainmodel.hh new file mode 100644 index 0000000000000000000000000000000000000000..ad1124dee9e731fe800d70938f2eba660b800f49 --- /dev/null +++ b/dumux/multidomain/common/multidomainmodel.hh @@ -0,0 +1,393 @@ +// -*- 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/>. * + *****************************************************************************/ +#ifndef DUMUX_COUPLED_MODEL_HH +#define DUMUX_COUPLED_MODEL_HH + +#include "coupledproperties.hh" +#include "coupledpropertydefaults.hh" +#include "coupledproblem.hh" +#include "couplednewtoncontroller.hh" +//#include "coupledjacobianassembler.hh" + +namespace Dumux +{ + +/*! + * \defgroup ModelCoupling Coupled implicit models + */ + + +/*! + * \ingroup ModelCoupling + * + * \brief The base class of models which consist of two arbitrary + * sub-models which are coupled + */ +template<class TypeTag> +class CoupledModel +{ + typedef typename GET_PROP_TYPE(TypeTag, Model) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod; + typedef typename GET_PROP_TYPE(TypeTag, NewtonController) NewtonController; + typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) JacobianAssembler; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + + typedef typename GET_PROP_TYPE(TypeTag, SubProblem1TypeTag) SubTypeTag1; + typedef typename GET_PROP_TYPE(TypeTag, SubProblem2TypeTag) SubTypeTag2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, Problem) SubProblem1; + typedef typename GET_PROP_TYPE(SubTypeTag2, Problem) SubProblem2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, Model) SubModel1; + typedef typename GET_PROP_TYPE(SubTypeTag2, Model) SubModel2; + + enum { + numEq1 = GET_PROP_VALUE(TypeTag, NumEq1), + numEq2 = GET_PROP_VALUE(TypeTag, NumEq2) + }; + +public: + /*! + * \brief Apply the initial conditions to the model. + * + * \param problem docme + * + */ + void init(Problem &problem) + { + problem_ = &problem; + + // the two sub models have already been initialized by the + // sub-problems! + jacAsm_ = new JacobianAssembler(); + jacAsm_->init(problem); + +// uCur_.resize(asImp_().numDofs()); +// uPrev_.resize(asImp_().numDofs()); + + uCur_.resize(jacAsm_->residual().size()); + uPrev_.resize(jacAsm_->residual().size()); + + uCur_= 0; + uPrev_= 0; + + typedef Dumux::CoupledCommon<TypeTag> Common; + Common::spliceSolVectors(subModel1().curSol(), + subModel2().curSol(), + uCur_); + Common::spliceSolVectors(subModel1().prevSol(), + subModel2().prevSol(), + uPrev_); + } + + Scalar globalResidual(const SolutionVector &u, SolutionVector &tmp) + { + DUNE_THROW(Dune::NotImplemented, ""); +#if 0 + SolutionVector tmpU(asImp_(), 0.0); + tmpU = uCur_; + uCur_ = u; + localJacobian_.evalGlobalResidual(tmp); + + Scalar result = tmp.two_norm(); + /* + Scalar result = 0; + for (int i = 0; i < (*tmp).size(); ++i) { + for (int j = 0; j < numEq; ++j) + result += std::abs((*tmp)[i][j]); + } + */ + uCur_ = tmpU; + return result; +#endif + }; + + /*! + * \brief Reference to the current solution as a block vector. + */ + const SolutionVector &curSol() const + { return uCur_; } + + /*! + * \brief Reference to the current solution as a block vector. + */ + SolutionVector &curSol() + { return uCur_; } + + /*! + * \brief Reference to the previous solution as a block vector. + */ + const SolutionVector &prevSol() const + { return uPrev_; } + + /*! + * \brief Reference to the previous solution as a block vector. + */ + SolutionVector &prevSol() + { return uPrev_; } + + /*! + * \brief Returns the operator assembler for the global jacobian of + * the problem. + */ + JacobianAssembler &jacobianAssembler() + { return *jacAsm_; } + const JacobianAssembler &jacobianAssembler() const + { return *jacAsm_; } + + /*! + * \brief A reference to the problem on which the model is applied. + */ + Problem &problem() + { return *problem_; } + /*! + * \copydoc problem() + */ + const Problem &problem() const + { return *problem_; } + + /*! + * \brief A reference to the problem on which the model is applied. + */ + SubProblem1 &subProblem1() + { return problem().subProblem1(); } + /*! + * \copydoc subProblem1() + */ + const SubProblem1 &subProblem1() const + { return problem().subProblem1(); } + + /*! + * \brief A reference to the problem on which the model is applied. + */ + SubProblem2 &subProblem2() + { return problem().subProblem2(); } + /*! + * \copydoc subProblem2() + */ + const SubProblem2 &subProblem2() const + { return problem().subProblem2(); } + + /*! + * \brief A reference to the first sub-problem's model. + */ + SubModel1 &subModel1() + { return subProblem1().model(); } + /*! + * \copydoc subModel1() + */ + const SubModel1 &subModel1() const + { return subProblem1().model(); } + + /*! + * \brief A reference to the second sub-problem's model. + */ + SubModel2 &subModel2() + { return subProblem2().model(); } + /*! + * \copydoc subModel2() + */ + const SubModel2 &subModel2() const + { return subProblem2().model(); } + + /*! + * \brief Try to progress the model to the next timestep. + * + * \param solver docme + * \param controller docme + * + */ + bool update(NewtonMethod &solver, + NewtonController &controller) + { +#if HAVE_VALGRIND + for (size_t i = 0; i < curSol().size(); ++i) + Valgrind::CheckDefined(curSol()[i]); +#endif // HAVE_VALGRIND + + asImp_().updateBegin(); + + bool converged = solver.execute(controller); + if (!converged) + asImp_().updateFailed(); + else + asImp_().updateSuccessful(); + +#if HAVE_VALGRIND + for (size_t i = 0; i < curSol().size(); ++i) { + Valgrind::CheckDefined(curSol()[i]); + } +#endif // HAVE_VALGRIND + + return converged; + } + + + /*! + * \brief Called by the update() method before it tries to + * apply the newton method. This is primary a hook + * which the actual model can overload. + */ + void updateBegin() + { + subModel1().updateBegin(); + subModel2().updateBegin(); + + typedef Dumux::CoupledCommon<TypeTag> Common; + Common::spliceSolVectors(subModel1().curSol(), subModel2().curSol(), uCur_); + } + + + /*! + * \brief Called by the update() method if it was + * successful. This is primary a hook which the actual + * model can overload. + */ + void updateSuccessful() + { + subModel1().updateSuccessful(); + subModel2().updateSuccessful(); + } + + /*! + * \brief Called by the problem if a timeintegration was + * successful, post processing of the solution is done and the + * result has been written to disk. + * + * This should perpare the model for the next time integration. + * Note, that the advanceTimeLevel() methods of the sub-models + * have already been called by the individual sub problems... + */ + void advanceTimeLevel() + { + typedef Dumux::CoupledCommon<TypeTag> Common; + // splice the two sub-vectors together + Common::spliceSolVectors(subModel1().curSol(), subModel2().curSol(), uCur_); + Common::spliceSolVectors(subModel1().prevSol(), subModel2().prevSol(), uPrev_); + }; + + /*! + * \brief Called by the update() method if a try was ultimately + * unsuccessful. This is primary a hook which the + * actual model can overload. + */ + void updateFailed() + { + subModel1().updateFailed(); + subModel2().updateFailed(); + + typedef Dumux::CoupledCommon<TypeTag> Common; + // splice the two sub-vectors together + Common::spliceSolVectors(subModel1().curSol(), subModel2().curSol(), uCur_); + }; + + /*! + * \brief Called by the update() method if a try was + * unsuccessful. This is primary a hook which the + * actual model can overload. + */ + void updateFailedTry() + { + subModel1().updateFailedTry(); + subModel2().updateFailedTry(); + + typedef Dumux::CoupledCommon<TypeTag> Common; + // splice the two sub-vectors together + Common::spliceSolVectors(subModel1().curSol(), subModel2().curSol(), uCur_); + }; + + /*! + * \brief Calculate the global residual. + * + * \param globResidual docme + * + * The global deflection of the mass balance from zero. + */ + void evalGlobalResidual(SolutionVector &globResidual) + { + DUNE_THROW(Dune::NotImplemented, ""); + } + + /*! + * \brief Serializes the current state of the model. + * + * \param res docme + * + */ + template <class Restarter> + void serialize(Restarter &res) + { + subProblem1().serialize(res); + subProblem2().serialize(res); + } + + /*! + * \brief Deserializes the state of the model. + * + * \param res docme + * + */ + template <class Restarter> + void deserialize(Restarter &res) + { + subProblem1().deserialize(res); + subProblem2().deserialize(res); + wasRestarted_ = true; + } + + /*! + * \brief Returns the number of global degrees of freedoms (DOFs) + */ + size_t numDofs() const + { + return subModel1().numDofs()*numEq1 + subModel2().numDofs()*numEq2; + } + + void resetJacobianAssembler() + { + delete jacAsm_; + jacAsm_ = new JacobianAssembler(asImp_(), problem()); + } + + +protected: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } + + // the problem we want to solve. defines the constitutive + // relations, material laws, etc. + Problem *problem_; + + // the jacobian assembler + JacobianAssembler *jacAsm_; + + // cur is the current solution, prev the solution of the previous + // time step + SolutionVector uCur_; + SolutionVector uPrev_; + + bool wasRestarted_; +}; +} + +#endif diff --git a/dumux/multidomain/common/multidomainnewtoncontroller.hh b/dumux/multidomain/common/multidomainnewtoncontroller.hh new file mode 100644 index 0000000000000000000000000000000000000000..d9639d630577a0c185e4167bd237da16f31b1d44 --- /dev/null +++ b/dumux/multidomain/common/multidomainnewtoncontroller.hh @@ -0,0 +1,603 @@ +// -*- 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 newton controller for coupled problems. +*/ +#ifndef DUMUX_COUPLED_NEWTON_CONTROLLER_HH +#define DUMUX_COUPLED_NEWTON_CONTROLLER_HH + +#include <dumux/common/exceptions.hh> + +#include <dumux/linear/linearsolverproperties.hh> +#include <dumux/linear/boxlinearsolver.hh> + +#include <dune/istl/overlappingschwarz.hh> +#include <dune/istl/schwarz.hh> +#include <dune/istl/preconditioners.hh> +#include <dune/istl/solvers.hh> +#include "dune/istl/owneroverlapcopy.hh" + +#include <dune/istl/io.hh> +#include <dune/common/mpihelper.hh> +#include <iostream> +#include <boost/format.hpp> + +#include <dune/pdelab/backend/istlsolverbackend.hh> + +#include "couplednewtonconvergencewriter.hh" + +/*! + * \file + * \brief Additional properties required for the coupled Newton controller + */ +namespace Dumux +{ +template <class TypeTag> +class CoupledNewtonController; + +namespace Properties +{ + +//! Specifies the implementation of the Newton controller +NEW_PROP_TAG(NewtonController); + +//! Specifies the type of the actual Newton method +NEW_PROP_TAG(NewtonMethod); + +//! specifies whether the convergence rate and the global residual +//! gets written out to disk for every newton iteration (default is false) +NEW_PROP_TAG(NewtonWriteConvergence); + +/*! + * \brief Specifies whether the update should be done using the line search + * method instead of the plain Newton method. + * + * Whether this property has any effect depends on wether the line + * search method is implemented for the actual model's Newton + * controller's update() method. By default line search is not used. + */ +NEW_PROP_TAG(NewtonUseLineSearch); + +//! the value for the relative error below which convergence is declared +NEW_PROP_TAG(NewtonRelTolerance); + +/*! + * \brief The number of iterations at which the Newton method + * should aim at. + * + * This is used to control the time step size. The heuristic used + * is to scale the last time step size by the deviation of the + * number of iterations used from the target steps. + */ +NEW_PROP_TAG(NewtonTargetSteps); + +//! Number of maximum iterations for the Newton method. +NEW_PROP_TAG(NewtonMaxSteps); + +// set default values for Newton +// they can be overwritten in the parameter file +SET_INT_PROP(CoupledModel, NewtonTargetSteps, 8); +SET_INT_PROP(CoupledModel, NewtonMaxSteps, 15); +SET_SCALAR_PROP(CoupledModel, NewtonRelTolerance, 1e-5); +SET_BOOL_PROP(CoupledModel, NewtonWriteConvergence, false); +} + + +/*! + * \brief Reference implementation of a newton controller for coupled problems. + * + * If you want to specialize only some methods but are happy with + * the defaults of the reference controller, derive your + * controller from this class and simply overload the required + * methods. + */ +template <class TypeTag> +class CoupledNewtonController +{ + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, NewtonController) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + typedef typename GET_PROP_TYPE(TypeTag, SubProblem1TypeTag) SubTypeTag1; + typedef typename GET_PROP_TYPE(TypeTag, SubProblem2TypeTag) SubTypeTag2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, GridView) GridView1; + typedef typename GET_PROP_TYPE(SubTypeTag2, GridView) GridView2; + + typedef CoupledNewtonConvergenceWriter<TypeTag> ConvergenceWriter; + typedef typename GET_PROP_TYPE(TypeTag, LinearSolver) LinearSolver; + +public: + CoupledNewtonController(const Problem &problem) + : endIterMsgStream_(std::ostringstream::out) + , linearSolver_(problem) + , convergenceWriter_(asImp_()) + { + verbose_ = true; + numSteps_ = 0; + + // maximum tolerated deflection between two iterations + setRelTolerance(GET_PARAM_FROM_GROUP(TypeTag, Scalar, Newton, RelTolerance)); + setTargetSteps(GET_PARAM_FROM_GROUP(TypeTag, Scalar, Newton, TargetSteps)); + setMaxSteps(GET_PARAM_FROM_GROUP(TypeTag, Scalar, Newton, MaxSteps)); + +// Writes out, where the relative tolerance is defined +// std::cout << "ParameterNewtonRelTol= " << PROP_DIAGNOSTIC(TypeTag, NewtonRelTolerance) << std::endl; + }; + + /*! + * \brief Destructor + */ + ~CoupledNewtonController() + { + }; + + /*! + * \brief Specifies if the newton method ought to be chatty. + * + * \param val docme + * + */ + void setVerbose(bool val) + { verbose_ = val; } + + /*! + * \brief Returns true if the newton method ought to be chatty. + */ + bool verbose() const + { return verbose_ && gridView_().comm().rank() == 0; } + + /*! + * \brief Set the maximum acceptable difference for convergence of + * any primary variable between two iterations. + * + * \param tolerance The maximum relative error between two Newton + * iterations at which the scheme is considered + * finished + */ + void setRelTolerance(Scalar tolerance) + { tolerance_ = tolerance; } + + /*! + * \brief Set the maximum acceptable residual norm reduction. + * + * \param tolerance The maximum reduction of the residual norm + * at which the scheme is considered finished + */ +// void setAbsTolerance(Scalar tolerance) +// { absoluteTolerance_ = tolerance; } + + /*! + * \brief Set the number of iterations at which the Newton method + * should aim at. + * + * This is used to control the time step size. The heuristic used + * is to scale the last time step size by the deviation of the + * number of iterations used from the target steps. + * + * \param targetSteps Number of iterations which are considered "optimal" + */ + void setTargetSteps(int targetSteps) + { targetSteps_ = targetSteps; } + + /*! + * \brief Set the number of iterations after which the Newton + * method gives up. + */ + void setMaxSteps(int maxSteps) + { maxSteps_ = maxSteps; } + + /*! + * \brief Returns true if another iteration should be done. + * + * \param uCurrentIter The solution of the current newton iteration + */ + bool newtonProceed(SolutionVector &uCurrentIter) + { + if (numSteps_ < 2) + return true; // we always do at least two iterations + else + if (numSteps_ >= maxSteps_) + { + // we have exceeded the allowed number of steps. if the + // relative error was reduced by a factor of at least 5, + // we proceed anyway + return error_*4.0 < lastError_ && !asImp_().newtonConverged(); + } + else + if (asImp_().newtonConverged()) + return false; // we are below the desired tolerance + + return true; // do another round + } + + /*! + * \brief Returns true if the error of the solution is below the + * tolerance. + */ + bool newtonConverged() const + { return error_ <= tolerance_; } + + /*! + * \brief Called before the newton method is applied to an + * non-linear system of equations. + * + * \param method docme + * \param uCurrentIter docme + * + */ + void newtonBegin(NewtonMethod &method, const SolutionVector &uCurrentIter) + { + method_ = &method; + numSteps_ = 0; + + if (GET_PARAM_FROM_GROUP(TypeTag, bool, Newton, WriteConvergence)) + convergenceWriter_.beginTimestep(); + } + + /*! + * \brief Indidicates the beginning of a newton iteration. + */ + void newtonBeginStep() + { lastError_ = error_; } + + /*! + * \brief Returns the number of steps done since newtonBegin() was + * called. + */ + int newtonNumSteps() + { return numSteps_; } + + + /*! + * \brief Update the error of the solution compared to the + * previous iteration. + * + * \param uLastIter docme + * \param deltaU docme + * + */ + void newtonUpdateRelError(const SolutionVector &uLastIter, + const SolutionVector &deltaU) + { + // calculate the relative error as the maximum relative + // deflection in any degree of freedom. + error_ = 0; + + SolutionVector uNewI = uLastIter; + uNewI -= deltaU; + + for (unsigned int i = 0; i < uLastIter.size(); ++i) { + for (unsigned int j = 0; j < uLastIter[i].size(); ++j) { + Scalar vertexError = std::abs(deltaU[i][j]); + vertexError /= std::max<Scalar>(1.0, std::abs(uLastIter[i][j] + uNewI[i][j])/2); + + error_ = std::max(error_, vertexError); + } + } + } + + + /*! + * \brief Solve the linear system of equations \f$ \mathbf{A}x - b + * = 0\f$. + * + * \param A docme + * \param x docme + * \param b docme + * + * Throws Dumux::NumericalProblem if the linear solver didn't + * converge. + */ + template <class Matrix, class Vector> + void newtonSolveLinear(Matrix &A, + Vector &x, + Vector &b) + { + // if the deflection of the newton method is large, we do not + // need to solve the linear approximation accurately. Assuming + // that the initial value for the delta vector u is quite + // close to the final value, a reduction of 6 orders of + // magnitude in the defect should be sufficient... + try { + int converged = linearSolver_.solve(A, x, b); + + // make sure all processes converged +#if HAVE_MPI + int convergedSend = 1; + MPI_Allreduce(/*sendBuf=*/&convergedSend, + /*recvBuf=*/&converged, + /*count=*/1, + MPI_INT, + MPI_MIN, + MPI_COMM_WORLD); +#endif + if (!converged) { + DUNE_THROW(NumericalProblem, + "Linear solver did not converge"); + } + } + catch (const Dune::MatrixBlockError &e) { + // make sure all processes converged +#if HAVE_MPI + int convergedSend = 0; + int converged; + + MPI_Allreduce(/*sendBuf=*/&convergedSend, + /*recvBuf=*/&converged, + /*count=*/1, + MPI_INT, + MPI_MIN, + MPI_COMM_WORLD); +#endif + + Dumux::NumericalProblem p; + std::string msg; + std::ostringstream ms(msg); + ms << e.what() << "M=" << A[e.r][e.c]; + p.message(ms.str()); + throw p; + } + catch (const Dune::Exception &e) { + // make sure all processes converged +#if HAVE_MPI + int convergedSend = 0; + int converged; + + MPI_Allreduce(/*sendBuf=*/&convergedSend, + /*recvBuf=*/&converged, + /*count=*/1, + MPI_INT, + MPI_MIN, + MPI_COMM_WORLD); +#endif + + Dumux::NumericalProblem p; + p.message(e.what()); + throw p; + } + } + + /*! + * \brief Update the current solution function with a delta vector. + * + * The error estimates required for the newtonConverged() and + * newtonProceed() methods should be updated here. + * + * Different update strategies, such as line search and chopped + * updates can be implemented. The default behaviour is just to + * subtract deltaU from uLastIter. + * + * \param uCurrentIter docme + * \param uLastIter The solution of the last iteration + * \param deltaU The delta as calculated from solving the linear + * system of equations. This parameter also stores + * the updated solution. + * + */ + void newtonUpdate(SolutionVector &uCurrentIter, + const SolutionVector &uLastIter, + const SolutionVector &deltaU) + { + if (GET_PARAM_FROM_GROUP(TypeTag, bool, Newton, WriteConvergence)) { + writeConvergence_(uLastIter, deltaU); + } + + newtonUpdateRelError(uLastIter, deltaU); + + uCurrentIter = uLastIter; + uCurrentIter -= deltaU; + } + + /*! + * \brief Indicates that one newton iteration was finished. + * + * \param uCurrentIter docme + * \param uLastIter The solution of the last iteration + * + */ + void newtonEndStep(SolutionVector &uCurrentIter, SolutionVector &uLastIter) + { + typedef Dumux::CoupledCommon<TypeTag> Common; + + Common::splitSolVector(this->model().curSol(), + this->model().subModel1().curSol(), + this->model().subModel2().curSol()); + + ++numSteps_; + + if (verbose()) + std::cout << "\rNewton iteration " << numSteps_ << " done: " + << "error=" << error_ << endIterMsg().str() << "\n"; + endIterMsgStream_.str(""); + } + + /*! + * \brief Indicates that we're done solving the non-linear system of equations. + */ + void newtonEnd() + { + if (GET_PARAM_FROM_GROUP(TypeTag, bool, Newton, WriteConvergence)) + convergenceWriter_.endTimestep(); + } + + /*! + * \brief Called if the newton method broke down. + * + * This method is called _after_ newtonEnd() + */ + void newtonFail() + { + numSteps_ = std::max(maxSteps_, targetSteps_*2); + } + + /*! + * \brief Called when the newton method was sucessful. + * + * This method is called _after_ newtonEnd() + */ + void newtonSucceed() + { + } + + /*! + * \brief Suggest a new time stepsize based on the old time step size. + * + * The default behaviour is to suggest the old time step size + * scaled by the ratio between the target iterations and the + * iterations required to actually solve the last time step. + * + * \param oldTimeStep docme + * + */ + Scalar suggestTimeStepSize(Scalar oldTimeStep) const + { + // be agressive reducing the timestep size but + // conservative when increasing it. the rationale is + // that we want to avoid failing in the next newton + // iteration which would require another linearization + // of the problem. + if (numSteps_ > targetSteps_) { + Scalar percent = ((Scalar) numSteps_ - targetSteps_)/targetSteps_; + return oldTimeStep/(1.0 + percent); + } + else { + /*Scalar percent = (Scalar(1))/targetSteps_; + return oldTimeStep*(1 + percent); + */ + Scalar percent = ((Scalar) targetSteps_ - numSteps_)/targetSteps_; + return oldTimeStep*(1.0 + percent/1.2); + } + } + + /*! + * \brief Returns a reference to the current newton method + * which is controlled by this controller. + */ + NewtonMethod &method() + { return *method_; } + + /*! + * \brief Returns a reference to the current newton method + * which is controlled by this controller. + */ + const NewtonMethod &method() const + { return *method_; } + + /*! + * \brief Returns a reference to the current numeric model. + */ + Model &model() + { return method_->model(); } + + /*! + * \brief Returns a const reference to the current numeric model. + */ + const Model &model() const + { return method_->model(); } + + std::ostringstream &endIterMsg() + { return endIterMsgStream_; } + + const GridView1 &gridView1() const + { return problem_().gridView1(); } + const GridView2 &gridView2() const + { return problem_().gridView2(); } + + /*! + * \brief the convergence writer produces the output + * + * \param uLastIter The solution of the last iteration + * \param deltaU The delta as calculated from solving the linear + * system of equations. This parameter also stores + * the updated solution. + * + */ + void writeConvergence_(const SolutionVector &uLastIter, + const SolutionVector &deltaU) + { + if (GET_PARAM_FROM_GROUP(TypeTag, bool, Newton, WriteConvergence)) { + convergenceWriter_.beginIteration(gridView1_(), gridView2_()); + convergenceWriter_.writeFields(uLastIter, deltaU); + convergenceWriter_.endIteration(); + }; + }; + + /*! + * \brief Returns a copy of the the grid view. + */ + const GridView gridView_() const + { return problem_().gridView(); } + + /*! + * \brief the subdomain gridviews + */ + const GridView1 gridView1_() const + { return problem_().subProblem1().gridView(); } + const GridView2 gridView2_() const + { return problem_().subProblem2().gridView(); } + + /*! + * \brief the coupled problem + */ + Problem &problem_() + { return method_->problem(); } + const Problem &problem_() const + { return method_->problem(); } + + // returns the actual implementation for the controller we do + // it this way in order to allow "poor man's virtual methods", + // i.e. methods of subclasses which can be called by the base + // class. + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } + + bool verbose_; + + std::ostringstream endIterMsgStream_; + NewtonMethod *method_; + + Scalar tolerance_; + Scalar error_; + Scalar lastError_; + + // optimal number of iterations we want to achieve + int targetSteps_; + // maximum number of iterations we do before giving up + int maxSteps_; + // actual number of steps done so far + int numSteps_; + + // the linear solver + LinearSolver linearSolver_; + + ConvergenceWriter convergenceWriter_; +}; + +} // namespace Dumux + +#endif diff --git a/dumux/multidomain/common/multidomainproblem.hh b/dumux/multidomain/common/multidomainproblem.hh new file mode 100644 index 0000000000000000000000000000000000000000..424796aec22f0b8cf1ece0c68d22c0fea1a8d4fa --- /dev/null +++ b/dumux/multidomain/common/multidomainproblem.hh @@ -0,0 +1,387 @@ +// -*- 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 Base class for problems which involve two sub problems + */ +#ifndef DUMUX_COUPLED_PROBLEM_HH +#define DUMUX_COUPLED_PROBLEM_HH + +#include "coupledmodel.hh" +#include "couplednewtoncontroller.hh" + +namespace Dumux +{ + +/*! + * \ingroup ModelCoupling + * \brief Base class for problems which involve two sub problems + * + * \todo Please doc me more! + */ +template<class TypeTag> +class CoupledProblem +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Problem) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod; + typedef typename GET_PROP_TYPE(TypeTag, NewtonController) NewtonController; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + + typedef typename GET_PROP_TYPE(TypeTag, SubProblem1TypeTag) SubTypeTag1; + typedef typename GET_PROP_TYPE(TypeTag, SubProblem2TypeTag) SubTypeTag2; + + typedef typename GET_PROP_TYPE(SubTypeTag1, Problem) SubProblem1; + typedef typename GET_PROP_TYPE(SubTypeTag2, Problem) SubProblem2; + +public: + CoupledProblem(TimeManager &timeManager) + : timeManager_(timeManager), + newtonMethod_(asImp_()), + newtonCtl_(asImp_()) + { }; + + /*! + * \brief Called by the Dumux::TimeManager in order to + * initialize the problem and the sub-problems. + * + * If you overload this method don't forget to call + * ParentType::init() + */ + void init() + { + // initialize the sub-problems + asImp_().subProblem1().init(); + asImp_().subProblem2().init(); + + // specify the elements which couple + asImp_().addMetaElements(); + + // set the initial condition of the model + model().init(asImp_()); + + // intialize lagrange multipliers + asImp_().initMortarElements(); + } + + /*! + * \brief This method writes the complete state of the problem + * to the harddisk. + * + * \param res docme + * + * The file will start with the prefix returned by the name() + * method, has the current time of the simulation clock in it's + * name and uses the extension <tt>.drs</tt>. (Dumux ReStart + * file.) See Dumux::Restart for details. + */ + template <class Restarter> + void serialize(Restarter &res) + { + } + + /*! + * \brief This method restores the complete state of the problem + * from disk. + * + * \param res docme + * + * It is the inverse of the serialize() method. + */ + template <class Restarter> + void deserialize(Restarter &res) + { + } + + /*! + * \name Simulation control + */ + // \{ + + /*! + * \brief Start the simulation procedure. + * + * \param dtInitial docme + * \param tEnd docme + * + * This method is usually called by the main() function and simply + * uses Dumux::TimeManager::runSimulation() to do the actual + * work. + */ + bool simulate(Scalar dtInitial, Scalar tEnd) + { + // set the initial time step and the time where the simulation ends + timeManager_.setEndTime(tEnd); + timeManager_.setTimeStepSize(dtInitial); + timeManager_.runSimulation(asImp_()); + return true; + }; + + + /*! + * \brief Called by the time manager before the time integration. Calls preTimeStep() + * of the subproblems. + */ + void preTimeStep() + { + asImp_().subProblem1().preTimeStep(); + asImp_().subProblem2().preTimeStep(); + } + + /*! + * \brief Called by Dumux::TimeManager in order to do a time + * integration on the model. + */ + void timeIntegration() + { + // TODO: should be called from the group Implicit + const int maxFails = + GET_PARAM_FROM_GROUP(TypeTag, int, Newton, MaxTimeStepDivisions); + for (int i = 0; i < maxFails; ++i) + { + if (model_.update(newtonMethod_, newtonCtl_)) + return; + + // update failed + Scalar dt = timeManager().timeStepSize(); + Scalar nextDt = dt / 2; + timeManager().setTimeStepSize(nextDt); + + std::cout << "Newton solver did not converge. Retrying with time step of " + << timeManager().timeStepSize() << "sec\n"; + } + + DUNE_THROW(Dune::MathError, + "Newton solver didn't converge after " + << maxFails + << " timestep divisions. dt=" + << timeManager().timeStepSize()); + } + + /*! + * \brief Called by the time manager after the time integration to + * do some post processing on the solution. Calls postTimeStep() + * of the subproblems. + */ + void postTimeStep() + { + asImp_().subProblem1().postTimeStep(); + asImp_().subProblem2().postTimeStep(); + } + + /*! + * \brief Called by Dumux::TimeManager whenever a solution for a + * timestep has been computed and the simulation time has + * been updated. + * + * \param dt docme + * + */ + Scalar nextTimeStepSize(const Scalar dt) + { + return newtonCtl_.suggestTimeStepSize(dt); + }; + + /*! + * \brief This method is called by the model if the update to the + * next time step failed completely. + */ + void updateSuccessful() + { + model_.updateSuccessful(); + }; + + /*! + * \brief Returns true if the current solution should be written to + * disk (i.e. as a VTK file) + * + * The default behaviour is to write out every the solution for + * very time step. This file is intented to be overwritten by the + * implementation. + */ + bool shouldWriteOutput() const + { return true; } + + /*! + * \brief Returns true if the current state of the simulation should be written to + * disk + */ + bool shouldWriteRestartFile() const + { return false; } + + /*! + * \brief Called by the time manager after the end of an episode. + */ + void episodeEnd() + { + std::cerr << "The end of an episode is reached, but the problem " + << "does not override the episodeEnd() method. " + << "Doing nothing!\n"; + } + + // \} + + /*! + * \brief The problem name. + * + * This is used as a prefix for files generated by the simulation. + * It could be either overwritten by the problem files, or simply + * declared over the setName() function in the application file. + */ + const char *name() const + { + return simname_.c_str(); + } + + /*! + * \brief Set the problem name. + * + * \param newName docme + * + * This function sets the simulation name, which should be called before + * the application porblem is declared! If not, the default name "sim" + * will be used. + */ + static void setName(const char *newName) + { + simname_ = newName; + } + + /*! + * \brief Returns TimeManager object used by the simulation + */ + TimeManager &timeManager() + { return timeManager_; } + + /*! + * \copydoc timeManager() + */ + const TimeManager &timeManager() const + { return timeManager_; } + + /*! + * \brief Returns NewtonControler object used by the simulation + */ + NewtonController &newtonController() + { return newtonCtl_; } + + /*! + * \brief Returns NewtonControler object used by the simulation + */ + const NewtonController &newtonController() const + { return newtonCtl_; } + + /*! + * \brief Returns numerical model used for the problem. + */ + Model &model() + { return model_; } + + /*! + * \copydoc model() + */ + const Model &model() const + { return model_; } + // \} + + void computeCouplingIndices() const + { DUNE_THROW(Dune::NotImplemented, "Coupled problems need to implement the computeCouplingIndices method!"); } + + SubProblem1 &subProblem1() + { DUNE_THROW(Dune::NotImplemented, "Coupled problems need to implement the subProblem1 method!"); } + const SubProblem1 &subProblem1() const + { DUNE_THROW(Dune::NotImplemented, "Coupled problems need to implement the subProblem1 method!"); } + + SubProblem2 &subProblem2() + { DUNE_THROW(Dune::NotImplemented, "Coupled problems need to implement the subProblem2 method!"); } + const SubProblem2 &subProblem2() const + { DUNE_THROW(Dune::NotImplemented, "Coupled problems need to implement the subProblem2 method!"); } + + + /*! + * \brief Called by the time manager after everything which can be + * done about the current time step is finished and the + * model should be prepared to do the next time integration. + */ + void advanceTimeLevel() + { + asImp_().subProblem1().advanceTimeLevel(); + asImp_().subProblem2().advanceTimeLevel(); + + model_.advanceTimeLevel(); + } + + /*! + * \brief Write the relevant quantities of the current solution into an VTK output file. + */ + void writeOutput() + { + // write the current result to disk + if (asImp_().shouldWriteOutput()) { + asImp_().subProblem1().writeOutput(); + asImp_().subProblem2().writeOutput(); + } + } + + /*! + * \brief Serialize the simulation's state to disk + */ + void serialize() + { + DUNE_THROW(Dune::NotImplemented, + "Dumux::CoupledProblem::serialize"); + } + +protected: + void addMetaElements() + {} + + void initMortarElements() + {} + + //! Returns the implementation of the problem (i.e. static polymorphism) + Implementation &asImp_() + { return *static_cast<Implementation *>(this); } + + //! \copydoc asImp_() + const Implementation &asImp_() const + { return *static_cast<const Implementation *>(this); } + +private: + // a string for the name of the current simulation, which could be + // set by means of an program argument, for example. + static std::string simname_; + + TimeManager &timeManager_; + NewtonMethod newtonMethod_; + NewtonController newtonCtl_; + Model model_; +}; +// definition of the static class member simname_, +// which is necessary because it is of type string. +template <class TypeTag> +std::string CoupledProblem<TypeTag>::simname_="simCoupled"; //initialized with default "sim" + +} + +#endif diff --git a/dumux/multidomain/common/multidomainproperties.hh b/dumux/multidomain/common/multidomainproperties.hh new file mode 100644 index 0000000000000000000000000000000000000000..154ea37252861c1f8b8d183741a025f66f348f36 --- /dev/null +++ b/dumux/multidomain/common/multidomainproperties.hh @@ -0,0 +1,117 @@ +// -*- 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/>. * + *****************************************************************************/ +#ifndef DUMUX_COUPLED_PROPERTIES_HH +#define DUMUX_COUPLED_PROPERTIES_HH + +#include <dune/istl/bvector.hh> +#include <dune/istl/bcrsmatrix.hh> +#include <dumux/nonlinear/newtonmethod.hh> + +#include <dumux/implicit/common/implicitproperties.hh> +#include <dumux/linear/linearsolverproperties.hh> + +#include <dumux/common/timemanager.hh> + +/*! + * \file + * \brief Specify properties required for the coupled model + */ +namespace Dumux +{ +namespace Properties +{ +/*! + * \addtogroup ModelCoupling + */ +// \{ + +////////////////////////////////////////////////////////////////// +// Type tags tags +////////////////////////////////////////////////////////////////// + +//! The type tag for problems which utilize the coupling approach +NEW_TYPE_TAG(CoupledModel, INHERITS_FROM(LinearSolverTypeTag, ImplicitBase)); + +//! The type tag from which sub-problems of coupling models inherit +NEW_TYPE_TAG(CoupledSubProblem); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +//! Specifies the type tag of the first sub-problem +NEW_PROP_TAG(SubProblem1TypeTag); + +//! Specifies the type tag of the second sub-problem +NEW_PROP_TAG(SubProblem2TypeTag); + +//! Specifies the type tag of the other sub-problem +NEW_PROP_TAG(OtherSubProblemTypeTag); + +//! Specifies the type tag of coupled problem +NEW_PROP_TAG(CoupledProblemTypeTag); + +//! Specifies the local jacobian of a meta element +NEW_PROP_TAG(CoupledLocalJacobian); + +//! Specifies the jacobian assembler +NEW_PROP_TAG(JacobianAssembler); + +//! Specifies a meta element +NEW_PROP_TAG(MetaElement); + +//! Specifies a list of meta elements +NEW_PROP_TAG(MetaElementList); + +//! Specifies the type of the jacobian matrix as used for the linear +//! solver +NEW_PROP_TAG(JacobianMatrix); + +//! specifies whether the convergence rate and the global residual +//! gets written out to disk for every newton iteration +NEW_PROP_TAG(NewtonWriteConvergence); + +//! the maximum allowed number of timestep divisions for the +//! Newton solver +NEW_PROP_TAG(NewtonMaxTimeStepDivisions); + +//! Specifies the model +NEW_PROP_TAG(Model); + +//! Specifies the time manager +NEW_PROP_TAG(TimeManager); + +//! Specifies the number of equations in the coupled model +NEW_PROP_TAG(NumEq); + +//! Specifies the number of equations in submodel 1 +NEW_PROP_TAG(NumEq1); + +//! Specifies the number of equations in submodel 2 +NEW_PROP_TAG(NumEq2); + +//! Specifies the fluidsystem that is used in the subdomains +NEW_PROP_TAG(FluidSystem); + +//! Specifies whether the enriched(mortar) coupling is used (set to false by default) +NEW_PROP_TAG(DoEnrichedCoupling); + +} +} +#endif diff --git a/dumux/multidomain/common/multidomainpropertydefaults.hh b/dumux/multidomain/common/multidomainpropertydefaults.hh new file mode 100644 index 0000000000000000000000000000000000000000..15ea99f7794972acf568c2db33e389d500c932bd --- /dev/null +++ b/dumux/multidomain/common/multidomainpropertydefaults.hh @@ -0,0 +1,163 @@ +// -*- 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/>. * + *****************************************************************************/ +#ifndef DUMUX_COUPLED_PROPERTY_DEFAULTS_HH +#define DUMUX_COUPLED_PROPERTY_DEFAULTS_HH + +#include "coupledcommon.hh" +#include "couplednewtoncontroller.hh" + +#include "coupledproperties.hh" + +namespace Dumux +{ +template <class TypeTag> class CoupledModel; +template <class TypeTag> class CoupledJacobianAssembler; +template <class TypeTag> class CoupledNewtonController; + +namespace Properties +{ + +/////////////////////////////////////7 +// Set property values for the coupled model +SET_BOOL_PROP(CoupledModel, DoEnrichedCoupling, false); +SET_TYPE_PROP(CoupledModel, Model, Dumux::CoupledModel<TypeTag>); +SET_TYPE_PROP(CoupledModel, JacobianAssembler, Dumux::CoupledJacobianAssembler<TypeTag>); +SET_PROP(CoupledModel, SolutionVector) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; +public: + typedef Dune::BlockVector<Dune::FieldVector<Scalar, numEq> > type; +}; + +//! use the plain newton method for the coupled problems by default +SET_TYPE_PROP(CoupledModel, NewtonMethod, Dumux::NewtonMethod<TypeTag>); + +//! use the plain newton controller for coupled problems by default +SET_TYPE_PROP(CoupledModel, NewtonController, Dumux::CoupledNewtonController<TypeTag>); + +//! Set the default type of the time manager for coupled models +SET_TYPE_PROP(CoupledModel, TimeManager, Dumux::TimeManager<TypeTag>); + + +SET_PROP(CoupledModel, JacobianMatrix) +{private: + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; +public: + typedef Dune::BCRSMatrix<Dune::FieldMatrix<Scalar, numEq, numEq> > type; +}; + +SET_PROP(CoupledModel, NumEq) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, SubProblem1TypeTag) TypeTag1; + typedef typename GET_PROP_TYPE(TypeTag, SubProblem2TypeTag) TypeTag2; + + enum { + numEq1 = GET_PROP_VALUE(TypeTag1, NumEq), + numEq2 = GET_PROP_VALUE(TypeTag2, NumEq) + }; + +public: + static const int value = numEq1; //TODO: why?? +}; + +SET_PROP(CoupledModel, NumEq1) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, SubProblem1TypeTag) TypeTag1; + enum {numEq = GET_PROP_VALUE(TypeTag1, NumEq)}; +public: + static const int value = numEq; +}; + +SET_PROP(CoupledModel, NumEq2) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, SubProblem2TypeTag) TypeTag2; + enum {numEq = GET_PROP_VALUE(TypeTag2, NumEq)}; +public: + static const int value = numEq; +}; + +SET_PROP(CoupledModel, MetaElementList) +{private: + typedef typename GET_PROP_TYPE(TypeTag, MetaElement) MetaElement; +public: + typedef std::vector<MetaElement*> type; +}; + +SET_PROP(CoupledModel, LinearSolver) +{public: + typedef Dumux::BoxBiCGStabILU0Solver<TypeTag> type; +}; + +SET_PROP(CoupledModel, LinearSolverResidualReduction) +{public: + static constexpr double value = 1e-6; +}; + +//! set the default number of maximum iterations for the linear solver +SET_PROP(CoupledModel, LinearSolverMaxIterations) +{public: + static constexpr int value = 250; +}; + +SET_INT_PROP(CoupledModel, NewtonMaxTimeStepDivisions, 10); + +// use the time manager for the coupled problem in the sub problems +SET_PROP(CoupledSubProblem, TimeManager) +{private: + typedef typename GET_PROP_TYPE(TypeTag, CoupledProblemTypeTag) CoupledTypeTag; +public: + typedef typename GET_PROP_TYPE(CoupledTypeTag, TimeManager) type; +}; + +// use the time manager for the coupled problem in the sub problems +SET_PROP(CoupledSubProblem, ParameterTree) +{private: + typedef typename GET_PROP_TYPE(TypeTag, CoupledProblemTypeTag) CoupledTypeTag; + typedef typename GET_PROP(CoupledTypeTag, ParameterTree) ParameterTree; +public: + typedef typename ParameterTree::type type; + + static type &tree() + { return ParameterTree::tree(); } + + static type &compileTimeParams() + { return ParameterTree::compileTimeParams(); } + + static type &runTimeParams() + { return ParameterTree::runTimeParams(); } + + static type &deprecatedRunTimeParams() + { return ParameterTree::deprecatedRunTimeParams(); } + + static type &unusedNewRunTimeParams() + { return ParameterTree::unusedNewRunTimeParams(); } + +}; + +// \} +} +} +#endif + diff --git a/dumux/multidomain/common/pdelablocaloperator.hh b/dumux/multidomain/common/pdelablocaloperator.hh new file mode 100644 index 0000000000000000000000000000000000000000..1c061e5170f39ac42ded4509a51f1ff375997af0 --- /dev/null +++ b/dumux/multidomain/common/pdelablocaloperator.hh @@ -0,0 +1,147 @@ +/***************************************************************************** + * Copyright (C) 2009-2010 by Bernd Flemisch * + * Institute for Modelling Hydraulic and Environmental Systems * + * University of Stuttgart, Germany * + * email: <givenname>.<name>@iws.uni-stuttgart.de * + * * + * 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 A local operator for PDELab which wraps the box models. + */ +#ifndef DUMUX_PDELAB_BOX_LOCAL_OPERATOR_HH +#define DUMUX_PDELAB_BOX_LOCAL_OPERATOR_HH + +#if ! HAVE_DUNE_PDELAB +#error "DUNE-PDELab must be available in order to include this file!" +#endif + +#include<dune/pdelab/localoperator/pattern.hh> +#include<dune/pdelab/localoperator/flags.hh> + +#include <dumux/implicit/box/boxproperties.hh> + +namespace Dumux { + +namespace PDELab { + +/*! + * \brief A local operator for PDELab which wraps the box models. + */ +template<class TypeTag> +class BoxLocalOperator + : +// : public Dune::PDELab::NumericalJacobianApplyVolume<BoxLocalOperatorPDELab<TypeTag> >, +//public Dune::PDELab::NumericalJacobianVolume<BoxLocalOperatorPDELab<TypeTag> >, + public Dune::PDELab::FullVolumePattern, + public Dune::PDELab::LocalOperatorDefaultFlags +{ + // copying the local operator for PDELab is not a good idea + BoxLocalOperator(const BoxLocalOperator &); + + typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; + +public: + // pattern assembly flags + enum { doPatternVolume = true }; + + // residual assembly flags + enum { doAlphaVolume = true }; + + + /*! + * \param model The physical model for the box scheme. + */ + BoxLocalOperator(Model &model) + : model_(model) + {} + + /*! + * \brief Volume integral depending on test and ansatz functions + * + * \tparam EG The entity geometry type from PDELab + * \tparam LFSU The type of the local function space of the ansatz functions + * \tparam X The type of the container for the coefficients for the ansatz functions + * \tparam LFSV The type of the local function space of the test functions + * \tparam R The range type (usually FieldVector<double>) + * + * \param eg The entity geometry object + * \param lfsu The local function space object of the ansatz functions + * \param x The object of the container for the coefficients for the ansatz functions + * \param lfsv The local function space object of the test functions + * \param r The object storing the volume integral + */ + template<typename EG, typename LFSU, typename X, typename LFSV, typename R> + void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, + const LFSV& lfsv, R& r) const + { + typedef typename LFSU::Traits::SizeType size_type; + + //enum { Green = JacobianAssembler::Green }; + //if (model_.jacobianAssembler().elementColor(eg.entity()) == Green) + // Green elements don't need to be reassembled + // return; + + model_.localResidual().eval(eg.entity()); + + int numVertices = x.size()/numEq; + for (size_type comp = 0; comp < r.size(); comp++) + r[comp] = model_.localResidual().residual(comp%numVertices)[comp/numVertices]; + } + + /*! + * \brief Jacobian of volume term + * + * \tparam EG The entity geometry type from PDELab + * \tparam LFSU The type of the local function space of the ansatz functions + * \tparam X The type of the container for the coefficients for the ansatz functions + * \tparam LFSV The type of the local function space of the test functions + * \tparam R The range type (usually FieldVector<double>) + * + * \param eg The entity geometry object + * \param lfsu The local function space object of the ansatz functions + * \param x The object of the container for the coefficients for the ansatz functions + * \param lfsv The local function space object of the test functions + * \param mat The object containing the local jacobian matrix + */ + template<typename EG, typename LFSU, typename X, typename LFSV, typename R> + void jacobian_volume (const EG& eg, + const LFSU& lfsu, + const X& x, + const LFSV& lfsv, + Dune::PDELab::LocalMatrix<R>& mat) const + { + typedef typename LFSU::Traits::SizeType size_type; + + model_.localJacobian().assemble(eg.entity()); + + int numVertices = x.size()/numEq; + for (size_type j=0; j<lfsu.size(); j++) { + for (size_type i=0; i<lfsu.size(); i++) { + mat(i,j) = (model_.localJacobian().mat(i%numVertices,j%numVertices))[i/numVertices][j/numVertices]; + } + } + } + +private: + Model& model_; +}; + +} // namespace PDELab +} // namespace Dumux + +#endif diff --git a/dumux/multidomain/common/subdomainpropertydefaults.hh b/dumux/multidomain/common/subdomainpropertydefaults.hh new file mode 100644 index 0000000000000000000000000000000000000000..80037ba46ab4c8d0d75f17210aae330bed25bc8e --- /dev/null +++ b/dumux/multidomain/common/subdomainpropertydefaults.hh @@ -0,0 +1,80 @@ +/***************************************************************************** + * 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/>. * + *****************************************************************************/ +#ifndef DUMUX_SUBDOMAIN_PROPERTY_DEFAULTS_HH +#define DUMUX_SUBDOMAIN_PROPERTY_DEFAULTS_HH + +#include <dune/grid/multidomaingrid.hh> +#include <dumux/implicit/pdelab/pdelabadapter.hh> +#include <dumux/implicit/common/boxcouplinglocalresidual.hh> +#include <dumux/modelcoupling/common/multidomainboxlocaloperator.hh> +#include "coupledproperties.hh" + +/*! + * \file + * \brief Specify default properties required in the subdomains of dune-multidomain + */ +namespace Dumux +{ +namespace Properties +{ +//! The type tag for problems which use dune-multidomain +NEW_TYPE_TAG(SubDomain, INHERITS_FROM(BoxPDELab, CoupledSubProblem)); + +////////////////////////////////////// +// Set property values +////////////////////////////////////// + +// Specifies the grid type for the subdomains +SET_PROP(SubDomain, Grid) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, CoupledProblemTypeTag) CoupledTypeTag; + typedef typename GET_PROP_TYPE(CoupledTypeTag, Grid) HostGrid; + typedef typename Dune::mdgrid::FewSubDomainsTraits<HostGrid::dimension,4> MDGridTraits; + typedef typename Dune::MultiDomainGrid<HostGrid, MDGridTraits> Grid; + +public: + typedef typename Grid::SubDomainGrid type; +}; + +// Set the default BaseLocalResidual to BoxCouplingLocalResidual +SET_TYPE_PROP(SubDomain, BaseLocalResidual, BoxCouplingLocalResidual<TypeTag>); + +// set the local operator used for submodels +SET_TYPE_PROP(SubDomain, LocalOperator, + Dumux::PDELab::MultiDomainBoxLocalOperator<TypeTag>); + + +// set the grid functions space for the sub-models +SET_PROP(SubDomain, ScalarGridFunctionSpace) +{ + private: + typedef typename GET_PROP_TYPE(TypeTag, LocalFEMSpace) FEM; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Constraints) Constraints; + enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; + public: + typedef Dune::PDELab::GridFunctionSpace<GridView, FEM, Constraints, + Dune::PDELab::ISTLVectorBackend<1> > type; +}; + +// \} + +} +} + +#endif