diff --git a/dumux/boxmodels/common/boxlocaljacobian.hh b/dumux/boxmodels/common/boxlocaljacobian.hh index f9326416f21caa5c19f970f35aedbed3d920b3a7..ae1da06f025141e543e0d76e4e6d90f3fc5c9bc7 100644 --- a/dumux/boxmodels/common/boxlocaljacobian.hh +++ b/dumux/boxmodels/common/boxlocaljacobian.hh @@ -1,3 +1,77 @@ -#warning This file is deprecated. Include dumux/implicit/box/boxlocaljacobian.hh instead. +// -*- 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 Caculates the Jacobian of the local residual for box models + */ +#ifndef DUMUX_BOX_LOCAL_JACOBIAN_HH +#define DUMUX_BOX_LOCAL_JACOBIAN_HH -#include <dumux/implicit/box/boxlocaljacobian.hh> +#include <dumux/implicit/common/implicitlocaljacobian.hh> + +namespace Dumux +{ +/*! + * \ingroup BoxModel + * \ingroup BoxLocalJacobian + * \brief Calculates the Jacobian of the local residual for box models + * + * The default behavior is to use numeric differentiation, i.e. + * forward or backward differences (2nd order), or central + * differences (3rd order). The method used is determined by the + * "NumericDifferenceMethod" property: + * + * - if the value of this property is smaller than 0, backward + * differences are used, i.e.: + * \f[ + \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon} + * \f] + * + * - if the value of this property is 0, central + * differences are used, i.e.: + * \f[ + \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon} + * \f] + * + * - if the value of this property is larger than 0, forward + * differences are used, i.e.: + * \f[ + \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x)}{\epsilon} + * \f] + * + * Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ + * is the value of a sub-control volume's primary variable at the + * evaluation point and \f$\epsilon\f$ is a small value larger than 0. + */ +template<class TypeTag> +class BoxLocalJacobian : public ImplicitLocalJacobian<TypeTag> +{ + typedef ImplicitLocalJacobian<TypeTag> ParentType; + + // copying a local jacobian is not a good idea + BoxLocalJacobian(const BoxLocalJacobian &); + +public: + DUNE_DEPRECATED_MSG("Use ImplicitLocalJacobian from dumux/implicit/common/implicitlocaljacobian.hh.") + BoxLocalJacobian() : ParentType() + { } +}; +} + +#endif diff --git a/dumux/boxmodels/common/porousmediaboxproblem.hh b/dumux/boxmodels/common/porousmediaboxproblem.hh index 63cd95cb08977333ad9fdab9814b3b4b3f695f80..c86c92e6d4a1fcd3c0f5c00a362823a30dbabe59 100644 --- a/dumux/boxmodels/common/porousmediaboxproblem.hh +++ b/dumux/boxmodels/common/porousmediaboxproblem.hh @@ -1,7 +1,6 @@ // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /***************************************************************************** - * 2012 by Bernd Flemisch * * See the file COPYING for full copying permissions. * * * * This program is free software: you can redistribute it and/or modify * diff --git a/dumux/freeflow/stokes/stokeslocaljacobian.hh b/dumux/freeflow/stokes/stokeslocaljacobian.hh index 9dee8d50b57c54f969b6c4709d4280468033e448..074443ef7c815683daec28b1ed10c7daf6237b22 100644 --- a/dumux/freeflow/stokes/stokeslocaljacobian.hh +++ b/dumux/freeflow/stokes/stokeslocaljacobian.hh @@ -25,7 +25,7 @@ #include <dune/istl/matrix.hh> #include "stokesproperties.hh" -#include <dumux/implicit/box/boxlocaljacobian.hh> +#include <dumux/implicit/common/implicitlocaljacobian.hh> namespace Dumux { @@ -38,13 +38,13 @@ namespace Dumux * The momentum balance equation uses larger epsilons than the rest. */ template<class TypeTag> -class StokesLocalJacobian : public BoxLocalJacobian<TypeTag> +class StokesLocalJacobian : public ImplicitLocalJacobian<TypeTag> { typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; public: - //! \copydoc BoxLocalJacobian::numericEpsilon() + //! \copydoc ImplicitLocalJacobian::numericEpsilon() Scalar numericEpsilon(const int scvIdx, const int pvIdx) const { diff --git a/dumux/implicit/box/boxfvelementgeometry.hh b/dumux/implicit/box/boxfvelementgeometry.hh index 2a8dcf4c97767c2b14ca59d88a5527e7f3f180ca..8f0811b4401dede22e891806ae014892943397ae 100644 --- a/dumux/implicit/box/boxfvelementgeometry.hh +++ b/dumux/implicit/box/boxfvelementgeometry.hh @@ -587,6 +587,7 @@ public: int numEdges; //!< number of edges int numFaces; //!< number of faces (0 in < 3D) int numSCV; //!< number of subcontrol volumes + int numNeighbors; //!< needed for compatibility with cc models int numFAP; //!< number of flux approximation points std::vector<ElementPointer> neighbors; //!< needed for compatibility with cc models @@ -614,6 +615,7 @@ public: numEdges = referenceElement.size(dim-1); numFaces = (dim<3)?0:referenceElement.size(1); numSCV = numVertices; + numNeighbors = 0; bool useTwoPointFlux = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, UseTwoPointFlux); diff --git a/dumux/implicit/box/boxlocaljacobian.hh b/dumux/implicit/box/boxlocaljacobian.hh deleted file mode 100644 index 7fc5140d2545e0ba467331e73bb39df09999ead6..0000000000000000000000000000000000000000 --- a/dumux/implicit/box/boxlocaljacobian.hh +++ /dev/null @@ -1,534 +0,0 @@ -// -*- 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 Caculates the Jacobian of the local residual for box models - */ -#ifndef DUMUX_BOX_LOCAL_JACOBIAN_HH -#define DUMUX_BOX_LOCAL_JACOBIAN_HH - -#include <dune/istl/matrix.hh> - -#include <dumux/common/math.hh> -#include "boxelementboundarytypes.hh" - -namespace Dumux -{ -/*! - * \ingroup BoxModel - * \ingroup BoxLocalJacobian - * \brief Calculates the Jacobian of the local residual for box models - * - * The default behavior is to use numeric differentiation, i.e. - * forward or backward differences (2nd order), or central - * differences (3rd order). The method used is determined by the - * "NumericDifferenceMethod" property: - * - * - if the value of this property is smaller than 0, backward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon} - * \f] - * - * - if the value of this property is 0, central - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon} - * \f] - * - * - if the value of this property is larger than 0, forward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x)}{\epsilon} - * \f] - * - * Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ - * is the value of a sub-control volume's primary variable at the - * evaluation point and \f$\epsilon\f$ is a small value larger than 0. - */ -template<class TypeTag> -class BoxLocalJacobian -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, LocalJacobian) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) JacobianAssembler; - - enum { - numEq = GET_PROP_VALUE(TypeTag, NumEq), - dim = GridView::dimension, - - Green = JacobianAssembler::Green - }; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; - typedef Dune::Matrix<MatrixBlock> LocalBlockMatrix; - - // copying a local jacobian is not a good idea - BoxLocalJacobian(const BoxLocalJacobian &); - -public: - BoxLocalJacobian() - { - numericDifferenceMethod_ = GET_PARAM_FROM_GROUP(TypeTag, int, Implicit, NumericDifferenceMethod); - Valgrind::SetUndefined(problemPtr_); - } - - - /*! - * \brief Initialize the local Jacobian object. - * - * At this point we can assume that everything has been allocated, - * although some objects may not yet be completely initialized. - * - * \param prob The problem which we want to simulate. - */ - void init(Problem &prob) - { - problemPtr_ = &prob; - localResidual_.init(prob); - - // assume quadrilinears as elements with most vertices - A_.setSize(2<<dim, 2<<dim); - storageJacobian_.resize(2<<dim); - } - - /*! - * \brief Assemble an element's local Jacobian matrix of the - * defect. - * - * \param element The DUNE Codim<0> entity which we look at. - */ - void assemble(const Element &element) - { - // set the current grid element and update the element's - // finite volume geometry - elemPtr_ = &element; - fvElemGeom_.update(gridView_(), element); - reset_(); - - bcTypes_.update(problem_(), element_(), fvElemGeom_); - - // this is pretty much a HACK because the internal state of - // the problem is not supposed to be changed during the - // evaluation of the residual. (Reasons: It is a violation of - // abstraction, makes everything more prone to errors and is - // not thread save.) The real solution are context objects! - problem_().updateCouplingParams(element_()); - - // set the hints for the volume variables - model_().setHints(element, prevVolVars_, curVolVars_); - - // update the secondary variables for the element at the last - // and the current time levels - prevVolVars_.update(problem_(), - element_(), - fvElemGeom_, - true /* isOldSol? */); - - curVolVars_.update(problem_(), - element_(), - fvElemGeom_, - false /* isOldSol? */); - - // update the hints of the model - model_().updateCurHints(element, curVolVars_); - - // calculate the local residual - localResidual().eval(element_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - residual_ = localResidual().residual(); - storageTerm_ = localResidual().storageTerm(); - - model_().updatePVWeights(element_(), curVolVars_); - - // calculate the local jacobian matrix - int numVertices = fvElemGeom_.numVertices; - ElementSolutionVector partialDeriv(numVertices); - PrimaryVariables storageDeriv; - for (int j = 0; j < numVertices; j++) { - for (int pvIdx = 0; pvIdx < numEq; pvIdx++) { - asImp_().evalPartialDerivative_(partialDeriv, - storageDeriv, - j, - pvIdx); - - // update the local stiffness matrix with the current partial - // derivatives - updateLocalJacobian_(j, - pvIdx, - partialDeriv, - storageDeriv); - } - } - } - - /*! - * \brief Returns a reference to the object which calculates the - * local residual. - */ - const LocalResidual &localResidual() const - { return localResidual_; } - - /*! - * \brief Returns a reference to the object which calculates the - * local residual. - */ - LocalResidual &localResidual() - { return localResidual_; } - - /*! - * \brief Returns the Jacobian of the equations at vertex i to the - * primary variables at vertex j. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - * \param j The local vertex (or sub-control volume) index which holds - * primary variables - */ - const MatrixBlock &mat(const int i, const int j) const - { return A_[i][j]; } - - /*! - * \brief Returns the Jacobian of the storage term at vertex i. - * - * \param i The local vertex (or sub-control volume) index - */ - const MatrixBlock &storageJacobian(const int i) const - { return storageJacobian_[i]; } - - /*! - * \brief Returns the residual of the equations at vertex i. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - */ - const PrimaryVariables &residual(const int i) const - { return residual_[i]; } - - /*! - * \brief Returns the storage term for vertex i. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - */ - const PrimaryVariables &storageTerm(const int i) const - { return storageTerm_[i]; } - - /*! - * \brief Returns the epsilon value which is added and removed - * from the current solution. - * - * \param scvIdx The local index of the element's vertex for - * which the local derivative ought to be calculated. - * \param pvIdx The index of the primary variable which gets varied - */ - Scalar numericEpsilon(const int scvIdx, - const int pvIdx) const - { - // define the base epsilon as the geometric mean of 1 and the - // resolution of the scalar type. E.g. for standard 64 bit - // floating point values, the resolution is about 10^-16 and - // the base epsilon is thus approximately 10^-8. - /* - static const Scalar baseEps - = Dumux::geometricMean<Scalar>(std::numeric_limits<Scalar>::epsilon(), 1.0); - */ - static const Scalar baseEps = 1e-10; - assert(std::numeric_limits<Scalar>::epsilon()*1e4 < baseEps); - // the epsilon value used for the numeric differentiation is - // now scaled by the absolute value of the primary variable... - Scalar priVar = this->curVolVars_[scvIdx].priVar(pvIdx); - return baseEps*(std::abs(priVar) + 1.0); - } - -protected: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } - - /*! - * \brief Returns a reference to the problem. - */ - const Problem &problem_() const - { - Valgrind::CheckDefined(problemPtr_); - return *problemPtr_; - }; - - /*! - * \brief Returns a reference to the grid view. - */ - const GridView &gridView_() const - { return problem_().gridView(); } - - /*! - * \brief Returns a reference to the element. - */ - const Element &element_() const - { - Valgrind::CheckDefined(elemPtr_); - return *elemPtr_; - }; - - /*! - * \brief Returns a reference to the model. - */ - const Model &model_() const - { return problem_().model(); }; - - /*! - * \brief Returns a reference to the jacobian assembler. - */ - const JacobianAssembler &jacAsm_() const - { return model_().jacobianAssembler(); } - - /*! - * \brief Returns a reference to the vertex mapper. - */ - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); }; - - /*! - * \brief Reset the local jacobian matrix to 0 - */ - void reset_() - { - int n = element_().template count<dim>(); - for (int i = 0; i < n; ++ i) { - storageJacobian_[i] = 0.0; - for (int j = 0; j < n; ++ j) { - A_[i][j] = 0.0; - } - } - } - - /*! - * \brief Compute the partial derivatives to a primary variable at - * an degree of freedom. - * - * This method can be overwritten by the implementation if a - * better scheme than numerical differentiation is available. - * - * The default implementation of this method uses numeric - * differentiation, i.e. forward or backward differences (2nd - * order), or central differences (3rd order). The method used is - * determined by the "NumericDifferenceMethod" property: - * - * - if the value of this property is smaller than 0, backward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon} - * \f] - * - * - if the value of this property is 0, central - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon} - * \f] - * - * - if the value of this property is larger than 0, forward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x)}{\epsilon} - * \f] - * - * Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ - * is the value of a sub-control volume's primary variable at the - * evaluation point and \f$\epsilon\f$ is a small value larger than 0. - * - * \param partialDeriv The vector storing the partial derivatives of all - * equations - * \param storageDeriv the mass matrix contributions - * \param scvIdx The sub-control volume index of the current - * finite element for which the partial derivative - * ought to be calculated - * \param pvIdx The index of the primary variable at the scvIdx' - * sub-control volume of the current finite element - * for which the partial derivative ought to be - * calculated - */ - void evalPartialDerivative_(ElementSolutionVector &partialDeriv, - PrimaryVariables &storageDeriv, - const int scvIdx, - const int pvIdx) - { - int globalIdx = vertexMapper_().map(element_(), scvIdx, dim); - - PrimaryVariables priVars(model_().curSol()[globalIdx]); - VolumeVariables origVolVars(curVolVars_[scvIdx]); - - curVolVars_[scvIdx].setEvalPoint(&origVolVars); - Scalar eps = asImp_().numericEpsilon(scvIdx, pvIdx); - Scalar delta = 0; - - if (numericDifferenceMethod_ >= 0) { - // we are not using backward differences, i.e. we need to - // calculate f(x + \epsilon) - - // deflect primary variables - priVars[pvIdx] += eps; - delta += eps; - - // calculate the residual - curVolVars_[scvIdx].update(priVars, - problem_(), - element_(), - fvElemGeom_, - scvIdx, - false); - localResidual().eval(element_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - - // store the residual and the storage term - partialDeriv = localResidual().residual(); - storageDeriv = localResidual().storageTerm()[scvIdx]; - } - else { - // we are using backward differences, i.e. we don't need - // to calculate f(x + \epsilon) and we can recycle the - // (already calculated) residual f(x) - partialDeriv = residual_; - storageDeriv = storageTerm_[scvIdx]; - } - - - if (numericDifferenceMethod_ <= 0) { - // we are not using forward differences, i.e. we don't - // need to calculate f(x - \epsilon) - - // deflect the primary variables - priVars[pvIdx] -= delta + eps; - delta += eps; - - // calculate residual again - curVolVars_[scvIdx].update(priVars, - problem_(), - element_(), - fvElemGeom_, - scvIdx, - false); - localResidual().eval(element_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - partialDeriv -= localResidual().residual(); - storageDeriv -= localResidual().storageTerm()[scvIdx]; - } - else { - // we are using forward differences, i.e. we don't need to - // calculate f(x - \epsilon) and we can recycle the - // (already calculated) residual f(x) - partialDeriv -= residual_; - storageDeriv -= storageTerm_[scvIdx]; - } - - // divide difference in residuals by the magnitude of the - // deflections between the two function evaluation - partialDeriv /= delta; - storageDeriv /= delta; - - // restore the original state of the element's volume variables - curVolVars_[scvIdx] = origVolVars; - -#if HAVE_VALGRIND - for (unsigned i = 0; i < partialDeriv.size(); ++i) - Valgrind::CheckDefined(partialDeriv[i]); -#endif - } - - /*! - * \brief Updates the current local Jacobian matrix with the - * partial derivatives of all equations in regard to the - * primary variable 'pvIdx' at vertex 'scvIdx' . - */ - void updateLocalJacobian_(const int scvIdx, - const int pvIdx, - const ElementSolutionVector &partialDeriv, - const PrimaryVariables &storageDeriv) - { - // store the derivative of the storage term - for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - storageJacobian_[scvIdx][eqIdx][pvIdx] = storageDeriv[eqIdx]; - } - - for (int i = 0; i < fvElemGeom_.numVertices; i++) - { - // Green vertices are not to be changed! - if (jacAsm_().vertexColor(element_(), i) != Green) { - for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - // A[i][scvIdx][eqIdx][pvIdx] is the rate of change of - // the residual of equation 'eqIdx' at vertex 'i' - // depending on the primary variable 'pvIdx' at vertex - // 'scvIdx'. - this->A_[i][scvIdx][eqIdx][pvIdx] = partialDeriv[i][eqIdx]; - Valgrind::CheckDefined(this->A_[i][scvIdx][eqIdx][pvIdx]); - } - } - } - } - - const Element *elemPtr_; - FVElementGeometry fvElemGeom_; - - ElementBoundaryTypes bcTypes_; - - // The problem we would like to solve - Problem *problemPtr_; - - // secondary variables at the previous and at the current time - // levels - ElementVolumeVariables prevVolVars_; - ElementVolumeVariables curVolVars_; - - LocalResidual localResidual_; - - LocalBlockMatrix A_; - std::vector<MatrixBlock> storageJacobian_; - - ElementSolutionVector residual_; - ElementSolutionVector storageTerm_; - - int numericDifferenceMethod_; -}; -} - -#endif diff --git a/dumux/implicit/box/boxlocalresidual.hh b/dumux/implicit/box/boxlocalresidual.hh index 8c02754133eec4a5cde1c8afdbff9bbc3d93ece1..3b8fb1a63a8578a11a886719f474c48ca09f53e2 100644 --- a/dumux/implicit/box/boxlocalresidual.hh +++ b/dumux/implicit/box/boxlocalresidual.hh @@ -27,6 +27,7 @@ #include <dune/grid/common/geometry.hh> #include <dumux/common/valgrind.hh> +#include <dumux/implicit/common/implicitlocalresidual.hh> #include "boxproperties.hh" @@ -35,18 +36,16 @@ namespace Dumux /*! * \ingroup BoxModel * \ingroup BoxLocalResidual - * \brief Element-wise calculation of the residual matrix for models - * based on the box scheme. + * \brief Element-wise calculation of the residual for models + * based on the fully implicit box scheme. * * \todo Please doc me more! */ template<class TypeTag> -class BoxLocalResidual +class BoxLocalResidual : public ImplicitLocalResidual<TypeTag> { -private: - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + typedef ImplicitLocalResidual<TypeTag> ParentType; + friend class ImplicitLocalResidual<TypeTag>; typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; @@ -63,273 +62,18 @@ private: typedef typename Dune::GenericReferenceElements<CoordScalar, dim> ReferenceElements; typedef typename Dune::GenericReferenceElement<CoordScalar, dim> ReferenceElement; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; // copying the local residual class is not a good idea BoxLocalResidual(const BoxLocalResidual &); public: - BoxLocalResidual() + BoxLocalResidual() : ParentType() { } - ~BoxLocalResidual() - { } - - /*! - * \brief Initialize the local residual. - * - * This assumes that all objects of the simulation have been fully - * allocated but not necessarily initialized completely. - * - * \param problem The representation of the physical problem to be - * solved. - */ - void init(Problem &problem) - { problemPtr_ = &problem; } - - /*! - * \brief Compute the local residual, i.e. the deviation of the - * equations from zero. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - */ - void eval(const Element &element) - { - FVElementGeometry fvGeometry; - - fvGeometry.update(gridView_(), element); - fvElemGeomPtr_ = &fvGeometry; - - ElementVolumeVariables volVarsPrev, volVarsCur; - // update the hints - model_().setHints(element, volVarsPrev, volVarsCur); - - volVarsPrev.update(problem_(), - element, - fvGeometry_(), - true /* oldSol? */); - volVarsCur.update(problem_(), - element, - fvGeometry_(), - false /* oldSol? */); - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - - // this is pretty much a HACK because the internal state of - // the problem is not supposed to be changed during the - // evaluation of the residual. (Reasons: It is a violation of - // abstraction, makes everything more prone to errors and is - // not thread save.) The real solution are context objects! - problem_().updateCouplingParams(element); - - asImp_().eval(element, fvGeometry_(), volVarsPrev, volVarsCur, bcTypes); - } - - /*! - * \brief Compute the storage term for the current solution. - * - * This can be used to figure out how much of each conservation - * quantity is inside the element. - * - * \param element The DUNE Codim<0> entity for which the storage - * term ought to be calculated - */ - void evalStorage(const Element &element) - { - elemPtr_ = &element; - - FVElementGeometry fvGeometry; - fvGeometry.update(gridView_(), element); - fvElemGeomPtr_ = &fvGeometry; - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - bcTypesPtr_ = &bcTypes; - - // no previous volume variables! - prevVolVarsPtr_ = 0; - - ElementVolumeVariables volVars; - - // update the hints - model_().setHints(element, volVars); - - // calculate volume current variables - volVars.update(problem_(), element, fvGeometry_(), false); - curVolVarsPtr_ = &volVars; - - asImp_().evalStorage_(); - } - - /*! - * \brief Compute the flux term for the current solution. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param curVolVars The volume averaged variables for all - * sub-contol volumes of the element - */ - void evalFluxes(const Element &element, - const ElementVolumeVariables &curVolVars) - { - elemPtr_ = &element; - - FVElementGeometry fvGeometry; - fvGeometry.update(gridView_(), element); - fvElemGeomPtr_ = &fvGeometry; - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - - residual_.resize(fvGeometry_().numVertices); - residual_ = 0; - - bcTypesPtr_ = &bcTypes; - prevVolVarsPtr_ = 0; - curVolVarsPtr_ = &curVolVars; - asImp_().evalFluxes_(); - } - - /*! - * \brief Compute the local residual, i.e. the deviation of the - * equations from zero. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param fvGeometry The finite-volume geometry of the element - * \param prevVolVars The volume averaged variables for all - * sub-control volumes of the element at the previous - * time level - * \param curVolVars The volume averaged variables for all - * sub-control volumes of the element at the current - * time level - * \param bcTypes The types of the boundary conditions for all - * vertices of the element - */ - void eval(const Element &element, - const FVElementGeometry &fvGeometry, - const ElementVolumeVariables &prevVolVars, - const ElementVolumeVariables &curVolVars, - const ElementBoundaryTypes &bcTypes) - { - Valgrind::CheckDefined(prevVolVars); - Valgrind::CheckDefined(curVolVars); - -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry.numVertices; i++) { - prevVolVars[i].checkDefined(); - curVolVars[i].checkDefined(); - } -#endif // HAVE_VALGRIND - - elemPtr_ = &element; - fvElemGeomPtr_ = &fvGeometry; - bcTypesPtr_ = &bcTypes; - prevVolVarsPtr_ = &prevVolVars; - curVolVarsPtr_ = &curVolVars; - - // resize the vectors for all terms - int numVerts = fvGeometry_().numVertices; - residual_.resize(numVerts); - storageTerm_.resize(numVerts); - - residual_ = 0.0; - storageTerm_ = 0.0; - - asImp_().evalFluxes_(); - -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) - Valgrind::CheckDefined(residual_[i]); -#endif // HAVE_VALGRIND - - asImp_().evalVolumeTerms_(); - -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) { - Valgrind::CheckDefined(residual_[i]); - } -#endif // HAVE_VALGRIND - - // evaluate the boundary conditions - asImp_().evalBoundary_(); - -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) - Valgrind::CheckDefined(residual_[i]); -#endif // HAVE_VALGRIND - } - - /*! - * \brief Returns the local residual for all sub-control - * volumes of the element. - */ - const ElementSolutionVector &residual() const - { return residual_; } - - /*! - * \brief Returns the local residual for a given sub-control - * volume of the element. - * - * \param scvIdx The local index of the sub-control volume - * (i.e. the element's local vertex index) - */ - const PrimaryVariables &residual(const int scvIdx) const - { return residual_[scvIdx]; } - - /*! - * \brief Returns the storage term for all sub-control volumes of the - * element. - */ - const ElementSolutionVector &storageTerm() const - { return storageTerm_; } - - /*! - * \brief Returns the storage term for a given sub-control volumes - * of the element. - */ - const PrimaryVariables &storageTerm(const int scvIdx) const - { return storageTerm_[scvIdx]; } - protected: - Implementation &asImp_() - { - assert(static_cast<Implementation*>(this) != 0); - return *static_cast<Implementation*>(this); - } - - const Implementation &asImp_() const - { - assert(static_cast<const Implementation*>(this) != 0); - return *static_cast<const Implementation*>(this); - } - - /*! - * \brief Evaluate the boundary conditions - * of the current element. - */ - void evalBoundary_() - { - if (bcTypes_().hasNeumann() || bcTypes_().hasOutflow()) - asImp_().evalBoundaryFluxes_(); -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) - Valgrind::CheckDefined(residual_[i]); -#endif // HAVE_VALGRIND - - if (bcTypes_().hasDirichlet()) - asImp_().evalDirichlet_(); - } - /*! * \brief Set the values of the Dirichlet boundary control volumes * of the current element. @@ -337,14 +81,14 @@ protected: void evalDirichlet_() { PrimaryVariables dirichletValues(0); - for (int scvIdx = 0; scvIdx < fvGeometry_().numVertices; ++scvIdx) { - const BoundaryTypes &bcTypes = bcTypes_(scvIdx); + for (int scvIdx = 0; scvIdx < this->fvGeometry_().numVertices; ++scvIdx) { + const BoundaryTypes &bcTypes = this->bcTypes_(scvIdx); if (bcTypes.hasDirichlet()) { // ask the problem for the dirichlet values - const VertexPointer vPtr = element_().template subEntity<dim>(scvIdx); + const VertexPointer vPtr = this->element_().template subEntity<dim>(scvIdx); Valgrind::SetUndefined(dirichletValues); - asImp_().problem_().dirichlet(dirichletValues, *vPtr); + this->asImp_().problem_().dirichlet(dirichletValues, *vPtr); // set the dirichlet conditions for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { @@ -353,10 +97,10 @@ protected: assert(0 <= pvIdx && pvIdx < numEq); Valgrind::CheckDefined(dirichletValues[pvIdx]); - residual_[scvIdx][eqIdx] = - curPriVar_(scvIdx, pvIdx) - dirichletValues[pvIdx]; + this->residual_[scvIdx][eqIdx] = + this->curPriVar_(scvIdx, pvIdx) - dirichletValues[pvIdx]; - storageTerm_[scvIdx][eqIdx] = 0.0; + this->storageTerm_[scvIdx][eqIdx] = 0.0; } } } @@ -369,11 +113,11 @@ protected: */ void evalBoundaryFluxes_() { - Dune::GeometryType geoType = element_().geometry().type(); + Dune::GeometryType geoType = this->element_().geometry().type(); const ReferenceElement &refElement = ReferenceElements::general(geoType); - IntersectionIterator isIt = gridView_().ibegin(element_()); - const IntersectionIterator &endIt = gridView_().iend(element_()); + IntersectionIterator isIt = this->gridView_().ibegin(this->element_()); + const IntersectionIterator &endIt = this->gridView_().iend(this->element_()); for (; isIt != endIt; ++isIt) { // handle only faces on the boundary @@ -392,19 +136,17 @@ protected: dim); int boundaryFaceIdx = - fvGeometry_().boundaryFaceIndex(faceIdx, faceVertIdx); + this->fvGeometry_().boundaryFaceIndex(faceIdx, faceVertIdx); // add the residual of all vertices of the boundary // segment - asImp_().evalNeumannSegment_(isIt, - scvIdx, - boundaryFaceIdx); + this->asImp_().evalNeumannSegment_(isIt, + scvIdx, + boundaryFaceIdx); // evaluate the outflow conditions at the boundary face - // ATTENTION: This is so far a beta version that is only for the 2p2c and 2p2cni model - // available and not thoroughly tested. - asImp_().evalOutflowSegment_(isIt, - scvIdx, - boundaryFaceIdx); + this->asImp_().evalOutflowSegment_(isIt, + scvIdx, + boundaryFaceIdx); } } } @@ -420,28 +162,28 @@ protected: { // temporary vector to store the neumann boundary fluxes PrimaryVariables neumannFlux(0.0); - const BoundaryTypes &bcTypes = bcTypes_(scvIdx); + const BoundaryTypes &bcTypes = this->bcTypes_(scvIdx); // deal with neumann boundaries if (bcTypes.hasNeumann()) { Valgrind::SetUndefined(neumannFlux); - problem_().boxSDNeumann(neumannFlux, - element_(), - fvGeometry_(), - *isIt, - scvIdx, - boundaryFaceIdx, - curVolVars_()); + this->problem_().boxSDNeumann(neumannFlux, + this->element_(), + this->fvGeometry_(), + *isIt, + scvIdx, + boundaryFaceIdx, + this->curVolVars_()); neumannFlux *= - fvGeometry_().boundaryFace[boundaryFaceIdx].area - * curVolVars_(scvIdx).extrusionFactor(); + this->fvGeometry_().boundaryFace[boundaryFaceIdx].area + * this->curVolVars_(scvIdx).extrusionFactor(); Valgrind::CheckDefined(neumannFlux); // set the neumann conditions for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { if (!bcTypes.isNeumann(eqIdx)) continue; - residual_[scvIdx][eqIdx] += neumannFlux[eqIdx]; + this->residual_[scvIdx][eqIdx] += neumannFlux[eqIdx]; } } } @@ -464,7 +206,7 @@ protected: { //calculate outflow fluxes PrimaryVariables values(0.0); - asImp_().computeFlux(values, boundaryFaceIdx, true); + this->asImp_().computeFlux(values, boundaryFaceIdx, true); Valgrind::CheckDefined(values); for (int equationIdx = 0; equationIdx < numEq; ++equationIdx) @@ -485,20 +227,20 @@ protected: { // calculate the mass flux over the faces and subtract // it from the local rates - for (int scvfIdx = 0; scvfIdx < fvGeometry_().numEdges; scvfIdx++) + for (int scvfIdx = 0; scvfIdx < this->fvGeometry_().numEdges; scvfIdx++) { - int i = fvGeometry_().subContVolFace[scvfIdx].i; - int j = fvGeometry_().subContVolFace[scvfIdx].j; + int i = this->fvGeometry_().subContVolFace[scvfIdx].i; + int j = this->fvGeometry_().subContVolFace[scvfIdx].j; PrimaryVariables flux; Valgrind::SetUndefined(flux); - asImp_().computeFlux(flux, scvfIdx); + this->asImp_().computeFlux(flux, scvfIdx); Valgrind::CheckDefined(flux); Scalar extrusionFactor = - (curVolVars_(i).extrusionFactor() - + curVolVars_(j).extrusionFactor()) + (this->curVolVars_(i).extrusionFactor() + + this->curVolVars_(j).extrusionFactor()) / 2; flux *= extrusionFactor; @@ -516,225 +258,13 @@ protected: // of sub-control volume i and _INTO_ sub-control volume // j, we need to add the flux to finite volume i and // subtract it from finite volume j - residual_[i] += flux; - residual_[j] -= flux; + this->residual_[i] += flux; + this->residual_[j] -= flux; } } - - /*! - * \brief Set the local residual to the storage terms of all - * sub-control volumes of the current element. - */ - void evalStorage_() - { - storageTerm_.resize(fvGeometry_().numVertices); - storageTerm_ = 0; - - // calculate the amount of conservation each quantity inside - // all sub control volumes - for (int scvIdx = 0; scvIdx < fvGeometry_().numVertices; scvIdx++) { - Valgrind::SetUndefined(storageTerm_[scvIdx]); - asImp_().computeStorage(storageTerm_[scvIdx], scvIdx, /*isOldSol=*/false); - storageTerm_[scvIdx] *= - fvGeometry_().subContVol[scvIdx].volume - * curVolVars_(scvIdx).extrusionFactor(); - Valgrind::CheckDefined(storageTerm_[scvIdx]); - } - } - - /*! - * \brief Add the change in the storage terms and the source term - * to the local residual of all sub-control volumes of the - * current element. - */ - void evalVolumeTerms_() - { - // evaluate the volume terms (storage + source terms) - for (int scvIdx = 0; scvIdx < fvGeometry_().numVertices; scvIdx++) - { - Scalar extrusionFactor = - curVolVars_(scvIdx).extrusionFactor(); - - PrimaryVariables values(0.0); - - // mass balance within the element. this is the - // \f$\frac{m}{\partial t}\f$ term if using implicit - // euler as time discretization. - // - // TODO (?): we might need a more explicit way for - // doing the time discretization... - Valgrind::SetUndefined(storageTerm_[scvIdx]); - Valgrind::SetUndefined(values); - asImp_().computeStorage(storageTerm_[scvIdx], scvIdx, false); - asImp_().computeStorage(values, scvIdx, true); - Valgrind::CheckDefined(storageTerm_[scvIdx]); - Valgrind::CheckDefined(values); - - storageTerm_[scvIdx] -= values; - storageTerm_[scvIdx] *= - fvGeometry_().subContVol[scvIdx].volume - / problem_().timeManager().timeStepSize() - * extrusionFactor; - residual_[scvIdx] += storageTerm_[scvIdx]; - - // subtract the source term from the local rate - Valgrind::SetUndefined(values); - asImp_().computeSource(values, scvIdx); - Valgrind::CheckDefined(values); - values *= fvGeometry_().subContVol[scvIdx].volume * extrusionFactor; - residual_[scvIdx] -= values; - - // make sure that only defined quantities were used - // to calculate the residual. - Valgrind::CheckDefined(residual_[scvIdx]); - } - } - - /*! - * \brief Returns a reference to the problem. - */ - const Problem &problem_() const - { return *problemPtr_; }; - - /*! - * \brief Returns a reference to the model. - */ - const Model &model_() const - { return problem_().model(); }; - - /*! - * \brief Returns a reference to the vertex mapper. - */ - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); }; - - /*! - * \brief Returns a reference to the grid view. - */ - const GridView &gridView_() const - { return problem_().gridView(); } - - /*! - * \brief Returns a reference to the current element. - */ - const Element &element_() const - { - Valgrind::CheckDefined(elemPtr_); - return *elemPtr_; - } - /*! - * \brief Returns a reference to the current element's finite - * volume geometry. - */ - const FVElementGeometry &fvGeometry_() const - { - Valgrind::CheckDefined(fvElemGeomPtr_); - return *fvElemGeomPtr_; - } - - /*! - * \brief Returns a reference to the primary variables of - * the last time step of the i'th - * sub-control volume of the current element. - */ - const PrimaryVariables &prevPriVars_(const int i) const - { - return prevVolVars_(i).priVars(); - } - - /*! - * \brief Returns a reference to the primary variables of the i'th - * sub-control volume of the current element. - */ - const PrimaryVariables &curPriVars_(const int i) const - { - return curVolVars_(i).priVars(); - } - - /*! - * \brief Returns the j'th primary of the i'th sub-control volume - * of the current element. - */ - Scalar curPriVar_(const int i, const int j) const - { - return curVolVars_(i).priVar(j); - } - - /*! - * \brief Returns a reference to the current volume variables of - * all sub-control volumes of the current element. - */ - const ElementVolumeVariables &curVolVars_() const - { - Valgrind::CheckDefined(curVolVarsPtr_); - return *curVolVarsPtr_; - } - - /*! - * \brief Returns a reference to the volume variables of the i-th - * sub-control volume of the current element. - */ - const VolumeVariables &curVolVars_(const int i) const - { - return curVolVars_()[i]; - } - - /*! - * \brief Returns a reference to the previous time step's volume - * variables of all sub-control volumes of the current - * element. - */ - const ElementVolumeVariables &prevVolVars_() const - { - Valgrind::CheckDefined(prevVolVarsPtr_); - return *prevVolVarsPtr_; - } - - /*! - * \brief Returns a reference to the previous time step's volume - * variables of the i-th sub-control volume of the current - * element. - */ - const VolumeVariables &prevVolVars_(const int i) const - { - return prevVolVars_()[i]; - } - - /*! - * \brief Returns a reference to the boundary types of all - * sub-control volumes of the current element. - */ - const ElementBoundaryTypes &bcTypes_() const - { - Valgrind::CheckDefined(bcTypesPtr_); - return *bcTypesPtr_; - } - - /*! - * \brief Returns a reference to the boundary types of the i-th - * sub-control volume of the current element. - */ - const BoundaryTypes &bcTypes_(const int i) const - { - return bcTypes_()[i]; - } - -protected: - ElementSolutionVector storageTerm_; - ElementSolutionVector residual_; - - // The problem we would like to solve - Problem *problemPtr_; - - const Element *elemPtr_; - const FVElementGeometry *fvElemGeomPtr_; - - // current and previous secondary variables for the element - const ElementVolumeVariables *prevVolVarsPtr_; - const ElementVolumeVariables *curVolVarsPtr_; - - const ElementBoundaryTypes *bcTypesPtr_; + const VertexMapper &vertexMapper_() const + { return this->problem_().vertexMapper(); }; }; } diff --git a/dumux/implicit/box/boxmodel.hh b/dumux/implicit/box/boxmodel.hh index 567d706dd7fafb52f8c4a9115904b634eefc243a..a73f4741e5d390771c31a6b9fb1733d031957448 100644 --- a/dumux/implicit/box/boxmodel.hh +++ b/dumux/implicit/box/boxmodel.hh @@ -28,7 +28,6 @@ #include "boxpropertydefaults.hh" #include "boxelementvolumevariables.hh" -#include "boxlocaljacobian.hh" #include "boxlocalresidual.hh" #include <dumux/parallel/vertexhandles.hh> diff --git a/dumux/implicit/box/boxpropertydefaults.hh b/dumux/implicit/box/boxpropertydefaults.hh index 49b96ba12db6d10b6c358677b627c877a04ede05..6e592e0b4519823b1b4a73f420ee25e681b6cb08 100644 --- a/dumux/implicit/box/boxpropertydefaults.hh +++ b/dumux/implicit/box/boxpropertydefaults.hh @@ -32,7 +32,6 @@ #include "boxmodel.hh" #include "boxfvelementgeometry.hh" #include "boxelementboundarytypes.hh" -#include "boxlocaljacobian.hh" #include "boxlocalresidual.hh" #include "boxelementvolumevariables.hh" #include "boxproperties.hh" @@ -64,9 +63,6 @@ SET_TYPE_PROP(BoxModel, BaseLocalResidual, Dumux::BoxLocalResidual<TypeTag>); //! Set the BaseModel to BoxModel SET_TYPE_PROP(BoxModel, BaseModel, Dumux::BoxModel<TypeTag>); -//! The local jacobian operator for the box scheme -SET_TYPE_PROP(BoxModel, LocalJacobian, Dumux::BoxLocalJacobian<TypeTag>); - //! An array of secondary variable containers SET_TYPE_PROP(BoxModel, ElementVolumeVariables, Dumux::BoxElementVolumeVariables<TypeTag>); diff --git a/dumux/implicit/cellcentered/cclocaljacobian.hh b/dumux/implicit/cellcentered/cclocaljacobian.hh deleted file mode 100644 index 1aa4d7ff50bf071ac15e734397c70fbcb1b64403..0000000000000000000000000000000000000000 --- a/dumux/implicit/cellcentered/cclocaljacobian.hh +++ /dev/null @@ -1,541 +0,0 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * Copyright (C) 2008-2009 by Andreas Lauser * - * Copyright (C) 2007-2009 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 Caculates the Jacobian of the local residual for box models - */ -#ifndef DUMUX_CC_LOCAL_JACOBIAN_HH -#define DUMUX_CC_LOCAL_JACOBIAN_HH - -#include <dune/istl/matrix.hh> - -#include <dumux/common/math.hh> -#include "ccelementboundarytypes.hh" - -namespace Dumux -{ -/*! - * \ingroup CCModel - * \ingroup CCLocalJacobian - * \brief Calculates the Jacobian of the local residual for box models - * - * The default behavior is to use numeric differentiation, i.e. - * forward or backward differences (2nd order), or central - * differences (3rd order). The method used is determined by the - * "NumericDifferenceMethod" property: - * - * - if the value of this property is smaller than 0, backward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon} - * \f] - * - * - if the value of this property is 0, central - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon} - * \f] - * - * - if the value of this property is larger than 0, forward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x)}{\epsilon} - * \f] - * - * Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ - * is the value of a sub-control volume's primary variable at the - * evaluation point and \f$\epsilon\f$ is a small value larger than 0. - */ -template<class TypeTag> -class CCLocalJacobian -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, LocalJacobian) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) JacobianAssembler; - - enum { - numEq = GET_PROP_VALUE(TypeTag, NumEq), - dim = GridView::dimension - }; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; - typedef Dune::Matrix<MatrixBlock> LocalBlockMatrix; - - // copying a local jacobian is not a good idea - CCLocalJacobian(const CCLocalJacobian &); - -public: - CCLocalJacobian() - { - numericDifferenceMethod_ = GET_PARAM(TypeTag, int, ImplicitNumericDifferenceMethod); - Valgrind::SetUndefined(problemPtr_); - } - - - /*! - * \brief Initialize the local Jacobian object. - * - * At this point we can assume that everything has been allocated, - * although some objects may not yet be completely initialized. - * - * \param prob The problem which we want to simulate. - */ - void init(Problem &prob) - { - problemPtr_ = &prob; - localResidual_.init(prob); - - // assume quadrilinears as elements with most vertices - A_.setSize(1, 2<<dim); - storageJacobian_.resize(1); - } - - /*! - * \brief Assemble an element's local Jacobian matrix of the - * defect. - * - * \param element The DUNE Codim<0> entity which we look at. - */ - void assemble(const Element &element) - { - // set the current grid element and update the element's - // finite volume geometry - elemPtr_ = &element; - fvElemGeom_.update(gridView_(), element); - reset_(); - - bcTypes_.update(problem_(), elem_(), fvElemGeom_); - - // this is pretty much a HACK because the internal state of - // the problem is not supposed to be changed during the - // evaluation of the residual. (Reasons: It is a violation of - // abstraction, makes everything more prone to errors and is - // not thread save.) The real solution are context objects! - problem_().updateCouplingParams(elem_()); - - // set the hints for the volume variables - model_().setHints(element, prevVolVars_, curVolVars_); - - // update the secondary variables for the element at the last - // and the current time levels - prevVolVars_.update(problem_(), - elem_(), - fvElemGeom_, - true /* isOldSol? */); - - curVolVars_.update(problem_(), - elem_(), - fvElemGeom_, - false /* isOldSol? */); - - // update the hints of the model - model_().updateCurHints(element, curVolVars_); - - // calculate the local residual - localResidual().eval(elem_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - residual_ = localResidual().residual(); - storageTerm_ = localResidual().storageTerm(); - - model_().updatePVWeights(elem_(), curVolVars_); - - // calculate the local jacobian matrix - int numNeighbors = fvElemGeom_.numNeighbors; - ElementSolutionVector partialDeriv(1); - PrimaryVariables storageDeriv(0.0); - for (int j = 0; j < numNeighbors; j++) { - for (int pvIdx = 0; pvIdx < numEq; pvIdx++) { - asImp_().evalPartialDerivative_(partialDeriv, - storageDeriv, - j, - pvIdx); - - // update the local stiffness matrix with the current partial - // derivatives - updateLocalJacobian_(j, - pvIdx, - partialDeriv, - storageDeriv); - } - } - } - - /*! - * \brief Returns a reference to the object which calculates the - * local residual. - */ - const LocalResidual &localResidual() const - { return localResidual_; } - - /*! - * \brief Returns a reference to the object which calculates the - * local residual. - */ - LocalResidual &localResidual() - { return localResidual_; } - - /*! - * \brief Returns the Jacobian of the equations at vertex i to the - * primary variables at vertex j. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - * \param j The local vertex (or sub-control volume) index which holds - * primary variables - */ - const MatrixBlock &mat(int i, int j) const - { return A_[i][j]; } - - /*! - * \brief Returns the Jacobian of the storage term at vertex i. - * - * \param i The local vertex (or sub-control volume) index - */ - const MatrixBlock &storageJacobian(int i) const - { return storageJacobian_[i]; } - - /*! - * \brief Returns the residual of the equations at vertex i. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - */ - const PrimaryVariables &residual(int i) const - { return residual_[i]; } - - /*! - * \brief Returns the storage term for vertex i. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - */ - const PrimaryVariables &storageTerm(int i) const - { return storageTerm_[i]; } - - /*! - * \brief Returns the epsilon value which is added and removed - * from the current solution. - * - * \param scvIdx The local index of the element's vertex for - * which the local derivative ought to be calculated. - * \param pvIdx The index of the primary variable which gets varied - */ - Scalar numericEpsilon(int scvIdx, - int pvIdx) const - { - // define the base epsilon as the geometric mean of 1 and the - // resolution of the scalar type. E.g. for standard 64 bit - // floating point values, the resolution is about 10^-16 and - // the base epsilon is thus approximately 10^-8. - /* - static const Scalar baseEps - = Dumux::geometricMean<Scalar>(std::numeric_limits<Scalar>::epsilon(), 1.0); - */ - static const Scalar baseEps = 1e-10; - assert(std::numeric_limits<Scalar>::epsilon()*1e4 < baseEps); - // the epsilon value used for the numeric differentiation is - // now scaled by the absolute value of the primary variable... - Scalar pv = this->curVolVars_[scvIdx].priVar(pvIdx); - return baseEps*(std::abs(pv) + 1.0); - } - -protected: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } - - /*! - * \brief Returns a reference to the problem. - */ - const Problem &problem_() const - { - Valgrind::CheckDefined(problemPtr_); - return *problemPtr_; - }; - - /*! - * \brief Returns a reference to the grid view. - */ - const GridView &gridView_() const - { return problem_().gridView(); } - - /*! - * \brief Returns a reference to the element. - */ - const Element &elem_() const - { - Valgrind::CheckDefined(elemPtr_); - return *elemPtr_; - }; - - /*! - * \brief Returns a reference to the model. - */ - const Model &model_() const - { return problem_().model(); }; - - /*! - * \brief Returns a reference to the jacobian assembler. - */ - const JacobianAssembler &jacAsm_() const - { return model_().jacobianAssembler(); } - - /*! - * \brief Returns a reference to the vertex mapper. - */ - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); }; - - /*! - * \brief Reset the local jacobian matrix to 0 - */ - void reset_() - { - for (int i = 0; i < 1; ++ i) { - storageJacobian_[i] = 0.0; - for (int j = 0; j < A_.M(); ++ j) { - A_[i][j] = 0.0; - } - } - } - - /*! - * \brief Compute the partial derivatives to a primary variable at - * an degree of freedom. - * - * This method can be overwritten by the implementation if a - * better scheme than numerical differentiation is available. - * - * The default implementation of this method uses numeric - * differentiation, i.e. forward or backward differences (2nd - * order), or central differences (3rd order). The method used is - * determined by the "NumericDifferenceMethod" property: - * - * - if the value of this property is smaller than 0, backward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x) - f(x - \epsilon)}{\epsilon} - * \f] - * - * - if the value of this property is 0, central - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x - \epsilon)}{2 \epsilon} - * \f] - * - * - if the value of this property is larger than 0, forward - * differences are used, i.e.: - * \f[ - \frac{\partial f(x)}{\partial x} \approx \frac{f(x + \epsilon) - f(x)}{\epsilon} - * \f] - * - * Here, \f$ f \f$ is the residual function for all equations, \f$x\f$ - * is the value of a sub-control volume's primary variable at the - * evaluation point and \f$\epsilon\f$ is a small value larger than 0. - * - * \param dest The vector storing the partial derivatives of all - * equations - * \param destStorage the mass matrix contributions - * \param scvIdx The sub-control volume index of the current - * finite element for which the partial derivative - * ought to be calculated - * \param pvIdx The index of the primary variable at the scvIdx' - * sub-control volume of the current finite element - * for which the partial derivative ought to be - * calculated - */ - void evalPartialDerivative_(ElementSolutionVector &dest, - PrimaryVariables &destStorage, - int neighborIdx, - int pvIdx) - { - const Element& neighbor = *(fvElemGeom_.neighbors[neighborIdx]); - FVElementGeometry neighborFVGeom; - neighborFVGeom.updateInner(neighbor); - - int globalIdx = problemPtr_->elementMapper().map(neighbor); - - PrimaryVariables priVars(model_().curSol()[globalIdx]); - VolumeVariables origVolVars(curVolVars_[neighborIdx]); - - curVolVars_[neighborIdx].setEvalPoint(&origVolVars); - Scalar eps = asImp_().numericEpsilon(neighborIdx, pvIdx); - Scalar delta = 0; - - if (numericDifferenceMethod_ >= 0) { - // we are not using backward differences, i.e. we need to - // calculate f(x + \epsilon) - - // deflect primary variables - priVars[pvIdx] += eps; - delta += eps; - - // calculate the residual - curVolVars_[neighborIdx].update(priVars, - problem_(), - neighbor, - neighborFVGeom, - /*scvIdx=*/0, - false); - localResidual().eval(elem_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - - // store the residual and the storage term - dest = localResidual().residual(); - if (neighborIdx == 0) - destStorage = localResidual().storageTerm()[neighborIdx]; - } - else { - // we are using backward differences, i.e. we don't need - // to calculate f(x + \epsilon) and we can recycle the - // (already calculated) residual f(x) - dest = residual_; - if (neighborIdx == 0) - destStorage = storageTerm_[neighborIdx]; - } - - - if (numericDifferenceMethod_ <= 0) { - // we are not using forward differences, i.e. we don't - // need to calculate f(x - \epsilon) - - // deflect the primary variables - priVars[pvIdx] -= delta + eps; - delta += eps; - - // calculate residual again - curVolVars_[neighborIdx].update(priVars, - problem_(), - neighbor, - neighborFVGeom, - /*scvIdx=*/0, - false); - localResidual().eval(elem_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - dest -= localResidual().residual(); - if (neighborIdx == 0) - destStorage -= localResidual().storageTerm()[neighborIdx]; - } - else { - // we are using forward differences, i.e. we don't need to - // calculate f(x - \epsilon) and we can recycle the - // (already calculated) residual f(x) - dest -= residual_; - if (neighborIdx == 0) - destStorage -= storageTerm_[neighborIdx]; - } - - // divide difference in residuals by the magnitude of the - // deflections between the two function evaluation - dest /= delta; - destStorage /= delta; - - // restore the original state of the element's volume variables - curVolVars_[neighborIdx] = origVolVars; - -#if HAVE_VALGRIND - for (unsigned i = 0; i < dest.size(); ++i) - Valgrind::CheckDefined(dest[i]); -#endif - } - - /*! - * \brief Updates the current local Jacobian matrix with the - * partial derivatives of all equations in regard to the - * primary variable 'pvIdx' at vertex 'scvIdx' . - */ - void updateLocalJacobian_(int neighborIdx, - int pvIdx, - const ElementSolutionVector &deriv, - const PrimaryVariables &storageDeriv) - { - // store the derivative of the storage term - if (neighborIdx == 0) - for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - storageJacobian_[neighborIdx][eqIdx][pvIdx] = storageDeriv[eqIdx]; - } - - for (int i = 0; i < 1; i++) - { - for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - // A[i][scvIdx][eqIdx][pvIdx] is the rate of change of - // the residual of equation 'eqIdx' at vertex 'i' - // depending on the primary variable 'pvIdx' at vertex - // 'scvIdx'. - this->A_[i][neighborIdx][eqIdx][pvIdx] = deriv[i][eqIdx]; - Valgrind::CheckDefined(this->A_[i][neighborIdx][eqIdx][pvIdx]); - } - } - } - - const Element *elemPtr_; - FVElementGeometry fvElemGeom_; - - ElementBoundaryTypes bcTypes_; - - // The problem we would like to solve - Problem *problemPtr_; - - // secondary variables at the previous and at the current time - // levels - ElementVolumeVariables prevVolVars_; - ElementVolumeVariables curVolVars_; - - LocalResidual localResidual_; - - LocalBlockMatrix A_; - std::vector<MatrixBlock> storageJacobian_; - - ElementSolutionVector residual_; - ElementSolutionVector storageTerm_; - - int numericDifferenceMethod_; -}; -} - -#endif diff --git a/dumux/implicit/cellcentered/cclocalresidual.hh b/dumux/implicit/cellcentered/cclocalresidual.hh index cdc914e8b2d0b9c446f6486eb2e8a92dcfca1881..abe2f9f0b53319fc00e1f2c0c5806eb0672132cc 100644 --- a/dumux/implicit/cellcentered/cclocalresidual.hh +++ b/dumux/implicit/cellcentered/cclocalresidual.hh @@ -31,6 +31,7 @@ #include <dune/grid/common/geometry.hh> #include <dumux/common/valgrind.hh> +#include <dumux/implicit/common/implicitlocalresidual.hh> #include "ccproperties.hh" @@ -39,18 +40,16 @@ namespace Dumux /*! * \ingroup CCModel * \ingroup CCLocalResidual - * \brief Element-wise calculation of the residual matrix for models - * based on the box scheme. + * \brief Element-wise calculation of the residual for models + * based on the fully implicit cell-centered scheme. * * \todo Please doc me more! */ template<class TypeTag> -class CCLocalResidual +class CCLocalResidual : public ImplicitLocalResidual<TypeTag> { -private: - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + typedef ImplicitLocalResidual<TypeTag> ParentType; + friend class ImplicitLocalResidual<TypeTag>; typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; @@ -62,302 +61,17 @@ private: typedef typename GridView::template Codim<0>::Entity Element; typedef typename GridView::template Codim<dim>::EntityPointer VertexPointer; typedef typename GridView::IntersectionIterator IntersectionIterator; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; // copying the local residual class is not a good idea CCLocalResidual(const CCLocalResidual &); public: - CCLocalResidual() - { } - - ~CCLocalResidual() + CCLocalResidual() : ParentType() { } - /*! - * \brief Initialize the local residual. - * - * This assumes that all objects of the simulation have been fully - * allocated but not necessarily initialized completely. - * - * \param prob The representation of the physical problem to be - * solved. - */ - void init(Problem &prob) - { problemPtr_ = &prob; } - - /*! - * \brief Compute the local residual, i.e. the deviation of the - * equations from zero. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - */ - void eval(const Element &element) - { - FVElementGeometry fvElemGeom; - - fvElemGeom.update(gridView_(), element); - fvElemGeomPtr_ = &fvElemGeom; - - ElementVolumeVariables volVarsPrev, volVarsCur; - // update the hints - model_().setHints(element, volVarsPrev, volVarsCur); - - volVarsPrev.update(problem_(), - element, - fvGeometry_(), - true /* oldSol? */); - volVarsCur.update(problem_(), - element, - fvGeometry_(), - false /* oldSol? */); - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - - // this is pretty much a HACK because the internal state of - // the problem is not supposed to be changed during the - // evaluation of the residual. (Reasons: It is a violation of - // abstraction, makes everything more prone to errors and is - // not thread save.) The real solution are context objects! - problem_().updateCouplingParams(element); - - asImp_().eval(element, fvGeometry_(), volVarsPrev, volVarsCur, bcTypes); - } - - /*! - * \brief Compute the storage term for the current solution. - * - * This can be used to figure out how much of each conservation - * quantity is inside the element. - * - * \param element The DUNE Codim<0> entity for which the storage - * term ought to be calculated - */ - void evalStorage(const Element &element) - { - elemPtr_ = &element; - - FVElementGeometry fvElemGeom; - fvElemGeom.update(gridView_(), element); - fvElemGeomPtr_ = &fvElemGeom; - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - bcTypesPtr_ = &bcTypes; - - // no previous volume variables! - prevVolVarsPtr_ = 0; - - ElementVolumeVariables volVars; - - // update the hints - model_().setHints(element, volVars); - - // calculate volume current variables - volVars.update(problem_(), element, fvGeometry_(), false); - curVolVarsPtr_ = &volVars; - - asImp_().evalStorage_(); - } - - /*! - * \brief Compute the flux term for the current solution. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param curVolVars The volume averaged variables for all - * sub-contol volumes of the element - */ - void evalFluxes(const Element &element, - const ElementVolumeVariables &curVolVars) - { - elemPtr_ = &element; - - FVElementGeometry fvElemGeom; - fvElemGeom.update(gridView_(), element); - fvElemGeomPtr_ = &fvElemGeom; - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - - residual_.resize(1); - residual_ = 0; - - bcTypesPtr_ = &bcTypes; - prevVolVarsPtr_ = 0; - curVolVarsPtr_ = &curVolVars; - asImp_().evalFluxes_(); - } - - /*! - * \brief Compute the local residual, i.e. the deviation of the - * equations from zero. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param fvElemGeom The finite-volume geometry of the element - * \param prevVolVars The volume averaged variables for all - * sub-control volumes of the element at the previous - * time level - * \param curVolVars The volume averaged variables for all - * sub-control volumes of the element at the current - * time level - * \param bcTypes The types of the boundary conditions for all - * vertices of the element - */ - void eval(const Element &element, - const FVElementGeometry &fvElemGeom, - const ElementVolumeVariables &prevVolVars, - const ElementVolumeVariables &curVolVars, - const ElementBoundaryTypes &bcTypes) - { - Valgrind::CheckDefined(prevVolVars); - Valgrind::CheckDefined(curVolVars); - -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvElemGeom.numNeighbors; i++) { - prevVolVars[i].checkDefined(); - curVolVars[i].checkDefined(); - } -#endif // HAVE_VALGRIND - - elemPtr_ = &element; - fvElemGeomPtr_ = &fvElemGeom; - bcTypesPtr_ = &bcTypes; - prevVolVarsPtr_ = &prevVolVars; - curVolVarsPtr_ = &curVolVars; - - // resize the vectors for all terms - residual_.resize(1); - storageTerm_.resize(1); - - residual_ = 0.0; - storageTerm_ = 0.0; - - asImp_().evalFluxes_(); - -#if !defined NDEBUG && HAVE_VALGRIND - Valgrind::CheckDefined(residual_[0]); -#endif // HAVE_VALGRIND - - asImp_().evalVolumeTerms_(); - -#if !defined NDEBUG && HAVE_VALGRIND - Valgrind::CheckDefined(residual_[0]); -#endif // HAVE_VALGRIND - - // evaluate the boundary conditions - asImp_().evalBoundary_(); - -#if !defined NDEBUG && HAVE_VALGRIND - Valgrind::CheckDefined(residual_[0]); -#endif // HAVE_VALGRIND - } - - /*! - * \brief Add Outflow boundary conditions for a single sub-control - * volume face to the local residual. - * - * \note This is so far an empty method doing not more than - * nothing. A beta version is available for the 2p2c and - * 2p2cni model. There you can find a sample implementation. - */ - void evalOutflowSegment(const IntersectionIterator &isIt, - int scvIdx, - int boundaryFaceIdx) - {} - - /*! - * \brief Returns the local residual for all sub-control - * volumes of the element. - */ - const ElementSolutionVector &residual() const - { return residual_; } - - /*! - * \brief Returns the local residual for a given sub-control - * volume of the element. - * - * \param scvIdx The local index of the sub-control volume - * (i.e. the element's local vertex index) - */ - const PrimaryVariables &residual(int scvIdx) const - { return residual_[scvIdx]; } - - /*! - * \brief Returns the storage term for all sub-control volumes of the - * element. - */ - const ElementSolutionVector &storageTerm() const - { return storageTerm_; } - - /*! - * \brief Returns the storage term for a given sub-control volumes - * of the element. - */ - const PrimaryVariables &storageTerm(int scvIdx) const - { return storageTerm_[scvIdx]; } - - void evalOutflowSegment(const IntersectionIterator &isIt) - { - const BoundaryTypes &bcTypes = this->bcTypes_(0); - - // deal with outflow boundaries - if (bcTypes.hasOutflow()) - { - PrimaryVariables values(0.0); - asImp_().computeFlux(values, - /*boundaryFaceIdx=*/isIt->indexInInside(), - true); - Valgrind::CheckDefined(values); - - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) - { - if (!bcTypes.isOutflow(eqIdx) ) - continue; - this->residual_[0][eqIdx] += values[eqIdx]; - } - } - } protected: - Implementation &asImp_() - { - assert(static_cast<Implementation*>(this) != 0); - return *static_cast<Implementation*>(this); - } - - const Implementation &asImp_() const - { - assert(static_cast<const Implementation*>(this) != 0); - return *static_cast<const Implementation*>(this); - } - - /*! - * \brief Evaluate the boundary conditions - * of the current element. - */ - void evalBoundary_() - { - if (bcTypes_().hasNeumann() || bcTypes_().hasOutflow()) - asImp_().evalBoundaryFluxes_(); - -#if !defined NDEBUG && HAVE_VALGRIND - Valgrind::CheckDefined(residual_[0]); -#endif // HAVE_VALGRIND - - if (bcTypes_().hasDirichlet()) - asImp_().evalDirichlet_(); - } /*! * \brief Set the values of the Dirichlet boundary control volumes @@ -365,15 +79,15 @@ protected: */ void evalDirichlet_() { - PrimaryVariables tmp(0); + PrimaryVariables dirichletValues(0); - const BoundaryTypes &bcTypes = bcTypes_(0); + const BoundaryTypes &bcTypes = this->bcTypes_(0); if (! bcTypes.hasDirichlet()) return; - Valgrind::SetUndefined(tmp); - // HACK: ask for Dirichlet value at element center - asImp_().problem_().dirichletAtPos(tmp, element_().geometry().center()); + Valgrind::SetUndefined(dirichletValues); + // HACK: ask for Dirichlet value at element center + this->asImp_().problem_().dirichletAtPos(dirichletValues, this->element_().geometry().center()); // set the dirichlet conditions for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { @@ -381,12 +95,12 @@ protected: continue; int pvIdx = bcTypes.eqToDirichletIndex(eqIdx); assert(0 <= pvIdx && pvIdx < numEq); - Valgrind::CheckDefined(tmp[pvIdx]); + Valgrind::CheckDefined(dirichletValues[pvIdx]); - residual_[0][eqIdx] = - (curPriVar_(0, pvIdx) - tmp[pvIdx]); + this->residual_[0][eqIdx] = + (this->curPriVar_(0, pvIdx) - dirichletValues[pvIdx]); - storageTerm_[0][eqIdx] = 0.0; + this->storageTerm_[0][eqIdx] = 0.0; } } @@ -396,8 +110,8 @@ protected: */ void evalBoundaryFluxes_() { - IntersectionIterator isIt = gridView_().ibegin(element_()); - const IntersectionIterator &endIt = gridView_().iend(element_()); + IntersectionIterator isIt = this->gridView_().ibegin(this->element_()); + const IntersectionIterator &endIt = this->gridView_().iend(this->element_()); for (; isIt != endIt; ++isIt) { // handle only faces on the boundary @@ -406,18 +120,15 @@ protected: // add the residual of all vertices of the boundary // segment - asImp_().evalNeumannSegment_(isIt); - + this->asImp_().evalNeumannSegment_(isIt); + // evaluate the outflow conditions at the boundary face - // ATTENTION: This is so far a beta version that is only for the 2p2c and 2p2cni model - // available and not thoroughly tested. - asImp_().evalOutflowSegment(isIt); + this->asImp_().evalOutflowSegment_(isIt); } } /*! - * \brief Add Neumann boundary conditions for a single sub-control - * volume face to the local residual. + * \brief Add Neumann boundary conditions for a single intersection */ void evalNeumannSegment_(const IntersectionIterator &isIt) { @@ -425,42 +136,66 @@ protected: PrimaryVariables values(0.0); BoundaryTypes bcTypes; - problem_().boundaryTypes(bcTypes, *isIt); + this->problem_().boundaryTypes(bcTypes, *isIt); // deal with neumann boundaries if (bcTypes.hasNeumann()) { Valgrind::SetUndefined(values); - problem_().boxSDNeumann(values, - element_(), - fvGeometry_(), - *isIt, - /*scvIdx=*/0, - /*boundaryFaceIdx=*/isIt->indexInInside(), - curVolVars_()); + this->problem_().boxSDNeumann(values, + this->element_(), + this->fvGeometry_(), + *isIt, + /*scvIdx=*/0, + /*boundaryFaceIdx=*/isIt->indexInInside(), + this->curVolVars_()); values *= isIt->geometry().volume() - * curVolVars_(0).extrusionFactor(); + * this->curVolVars_(0).extrusionFactor(); Valgrind::CheckDefined(values); // set the neumann conditions for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { if (!bcTypes.isNeumann(eqIdx)) continue; - residual_[0][eqIdx] += values[eqIdx]; + this->residual_[0][eqIdx] += values[eqIdx]; + } + } + } + + /*! + * \brief Add outflow boundary conditions for a single intersection + */ + void evalOutflowSegment_(const IntersectionIterator &isIt) + { + const BoundaryTypes &bcTypes = this->bcTypes_(0); + + // deal with outflow boundaries + if (bcTypes.hasOutflow()) + { + PrimaryVariables values(0.0); + this->asImp_().computeFlux(values, + /*boundaryFaceIdx=*/isIt->indexInInside(), + true); + Valgrind::CheckDefined(values); + + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + { + if (!bcTypes.isOutflow(eqIdx) ) + continue; + this->residual_[0][eqIdx] += values[eqIdx]; } } } /*! - * \brief Add the flux terms to the local residual of all - * sub-control volumes of the current element. + * \brief Add the flux terms to the local residual of the current element */ void evalFluxes_() { // calculate the mass flux over the faces and subtract // it from the local rates int faceIdx = -1; - IntersectionIterator isIt = gridView_().ibegin(element_()); - IntersectionIterator isEndIt = gridView_().iend(element_()); + IntersectionIterator isIt = this->gridView_().ibegin(this->element_()); + IntersectionIterator isEndIt = this->gridView_().iend(this->element_()); for (; isIt != isEndIt; ++isIt) { if (!isIt->neighbor()) continue; @@ -469,240 +204,14 @@ protected: PrimaryVariables flux; Valgrind::SetUndefined(flux); - asImp_().computeFlux(flux, faceIdx); + this->asImp_().computeFlux(flux, faceIdx); Valgrind::CheckDefined(flux); - flux *= curVolVars_(0).extrusionFactor(); - - // The balance equation for a finite volume is: - // - // dStorage/dt = Flux + Source - // - // where the 'Flux' and the 'Source' terms represent the - // mass per second which _ENTER_ the finite - // volume. Re-arranging this, we get - // - // dStorage/dt - Source - Flux = 0 - // - // Since the flux calculated by computeFlux() goes _OUT_ - // of sub-control volume i and _INTO_ sub-control volume - // j, we need to add the flux to finite volume i and - // subtract it from finite volume j - residual_[0] += flux; - } - } - - /*! - * \brief Set the local residual to the storage terms of all - * sub-control volumes of the current element. - */ - void evalStorage_() - { - storageTerm_.resize(1); - storageTerm_ = 0; - - // calculate the amount of conservation each quantity inside - // all sub control volumes - Valgrind::SetUndefined(storageTerm_[0]); - asImp_().computeStorage(storageTerm_[0], 0, /*isOldSol=*/false); - storageTerm_[0] *= fvGeometry_().subContVol[0].volume - * curVolVars_(0).extrusionFactor(); - Valgrind::CheckDefined(storageTerm_[0]); - } - - /*! - * \brief Add the change in the storage terms and the source term - * to the local residual of all sub-control volumes of the - * current element. - */ - void evalVolumeTerms_() - { - // evaluate the volume terms (storage + source terms) - for (int i=0; i < 1; i++) - { - Scalar extrusionFactor = - curVolVars_(i).extrusionFactor(); - - PrimaryVariables tmp(0.); - - // mass balance within the element. this is the - // \f$\frac{m}{\partial t}\f$ term if using implicit - // euler as time discretization. - // - // TODO (?): we might need a more explicit way for - // doing the time discretization... - Valgrind::SetUndefined(storageTerm_[i]); - Valgrind::SetUndefined(tmp); - asImp_().computeStorage(storageTerm_[i], i, false); - asImp_().computeStorage(tmp, i, true); - Valgrind::CheckDefined(storageTerm_[i]); - Valgrind::CheckDefined(tmp); + flux *= this->curVolVars_(0).extrusionFactor(); - storageTerm_[i] -= tmp; - storageTerm_[i] *= - fvGeometry_().subContVol[i].volume - / problem_().timeManager().timeStepSize() - * extrusionFactor; - residual_[i] += storageTerm_[i]; - - // subtract the source term from the local rate - Valgrind::SetUndefined(tmp); - asImp_().computeSource(tmp, i); - Valgrind::CheckDefined(tmp); - tmp *= fvGeometry_().subContVol[i].volume * extrusionFactor; - residual_[i] -= tmp; - - // make sure that only defined quantities were used - // to calculate the residual. - Valgrind::CheckDefined(residual_[i]); + this->residual_[0] += flux; } } - - /*! - * \brief Returns a reference to the problem. - */ - const Problem &problem_() const - { return *problemPtr_; }; - - /*! - * \brief Returns a reference to the model. - */ - const Model &model_() const - { return problem_().model(); }; - - /*! - * \brief Returns a reference to the vertex mapper. - */ - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); }; - - /*! - * \brief Returns a reference to the grid view. - */ - const GridView &gridView_() const - { return problem_().gridView(); } - - /*! - * \brief Returns a reference to the current element. - */ - const Element &element_() const - { - Valgrind::CheckDefined(elemPtr_); - return *elemPtr_; - } - - /*! - * \brief Returns a reference to the current element's finite - * volume geometry. - */ - const FVElementGeometry &fvGeometry_() const - { - Valgrind::CheckDefined(fvElemGeomPtr_); - return *fvElemGeomPtr_; - } - - /*! - * \brief Returns a reference to the primary variables of - * the last time step of the i'th - * sub-control volume of the current element. - */ - const PrimaryVariables &prevPriVars_(int i) const - { - return prevVolVars_(i).priVars(); - } - - /*! - * \brief Returns a reference to the primary variables of the i'th - * sub-control volume of the current element. - */ - const PrimaryVariables &curPriVars_(int i) const - { - return curVolVars_(i).priVars(); - } - - /*! - * \brief Returns the j'th primary of the i'th sub-control volume - * of the current element. - */ - Scalar curPriVar_(int i, int j) const - { - return curVolVars_(i).priVar(j); - } - - /*! - * \brief Returns a reference to the current volume variables of - * all sub-control volumes of the current element. - */ - const ElementVolumeVariables &curVolVars_() const - { - Valgrind::CheckDefined(curVolVarsPtr_); - return *curVolVarsPtr_; - } - - /*! - * \brief Returns a reference to the volume variables of the i-th - * sub-control volume of the current element. - */ - const VolumeVariables &curVolVars_(int i) const - { - return curVolVars_()[i]; - } - - /*! - * \brief Returns a reference to the previous time step's volume - * variables of all sub-control volumes of the current - * element. - */ - const ElementVolumeVariables &prevVolVars_() const - { - Valgrind::CheckDefined(prevVolVarsPtr_); - return *prevVolVarsPtr_; - } - - /*! - * \brief Returns a reference to the previous time step's volume - * variables of the i-th sub-control volume of the current - * element. - */ - const VolumeVariables &prevVolVars_(int i) const - { - return prevVolVars_()[i]; - } - - /*! - * \brief Returns a reference to the boundary types of all - * sub-control volumes of the current element. - */ - const ElementBoundaryTypes &bcTypes_() const - { - Valgrind::CheckDefined(bcTypesPtr_); - return *bcTypesPtr_; - } - - /*! - * \brief Returns a reference to the boundary types of the i-th - * sub-control volume of the current element. - */ - const BoundaryTypes &bcTypes_(int i) const - { - return bcTypes_()[i]; - } - -protected: - ElementSolutionVector storageTerm_; - ElementSolutionVector residual_; - - // The problem we would like to solve - Problem *problemPtr_; - - const Element *elemPtr_; - const FVElementGeometry *fvElemGeomPtr_; - - // current and previous secondary variables for the element - const ElementVolumeVariables *prevVolVarsPtr_; - const ElementVolumeVariables *curVolVarsPtr_; - - const ElementBoundaryTypes *bcTypesPtr_; }; } diff --git a/dumux/implicit/cellcentered/ccpropertydefaults.hh b/dumux/implicit/cellcentered/ccpropertydefaults.hh index 9e930ec6d0185f47b8dd2c84d74a97ff3073ae4f..57904da7ed7594bc6fa170f5647ba99aa81e61ff 100644 --- a/dumux/implicit/cellcentered/ccpropertydefaults.hh +++ b/dumux/implicit/cellcentered/ccpropertydefaults.hh @@ -36,7 +36,6 @@ #include "ccmodel.hh" #include "ccfvelementgeometry.hh" #include "ccelementboundarytypes.hh" -#include "cclocaljacobian.hh" #include "cclocalresidual.hh" #include "ccelementvolumevariables.hh" #include "ccproperties.hh" @@ -63,9 +62,6 @@ SET_TYPE_PROP(CCModel, BaseLocalResidual, Dumux::CCLocalResidual<TypeTag>); //! Set the BaseModel to CCModel SET_TYPE_PROP(CCModel, BaseModel, Dumux::CCModel<TypeTag>); -//! The local jacobian operator for the box scheme -SET_TYPE_PROP(CCModel, LocalJacobian, Dumux::CCLocalJacobian<TypeTag>); - //! An array of secondary variable containers SET_TYPE_PROP(CCModel, ElementVolumeVariables, Dumux::CCElementVolumeVariables<TypeTag>); diff --git a/dumux/implicit/common/implicitlocaljacobian.hh b/dumux/implicit/common/implicitlocaljacobian.hh index 7449afbcaf2a2f9854378c76b98db595379b0574..a285c9f2844e9a2eeee49537a1c28a614ffcd4a2 100644 --- a/dumux/implicit/common/implicitlocaljacobian.hh +++ b/dumux/implicit/common/implicitlocaljacobian.hh @@ -20,19 +20,17 @@ * \file * \brief Caculates the Jacobian of the local residual for box models */ -#ifndef DUMUX_BOX_LOCAL_JACOBIAN_HH -#define DUMUX_BOX_LOCAL_JACOBIAN_HH +#ifndef DUMUX_IMPLICIT_LOCAL_JACOBIAN_HH +#define DUMUX_IMPLICIT_LOCAL_JACOBIAN_HH #include <dune/istl/matrix.hh> - #include <dumux/common/math.hh> -#include "implicitelementboundarytypes.hh" namespace Dumux { /*! - * \ingroup BoxModel - * \ingroup BoxLocalJacobian + * \ingroup ImplicitModel + * \ingroup ImplicitLocalJacobian * \brief Calculates the Jacobian of the local residual for box models * * The default behavior is to use numeric differentiation, i.e. @@ -63,7 +61,7 @@ namespace Dumux * evaluation point and \f$\epsilon\f$ is a small value larger than 0. */ template<class TypeTag> -class BoxLocalJacobian +class ImplicitLocalJacobian { private: typedef typename GET_PROP_TYPE(TypeTag, LocalJacobian) Implementation; @@ -72,6 +70,7 @@ private: typedef typename GET_PROP_TYPE(TypeTag, Model) Model; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::Traits::template Codim<0>::EntityPointer ElementPointer; typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) JacobianAssembler; enum { @@ -94,11 +93,13 @@ private: typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; typedef Dune::Matrix<MatrixBlock> LocalBlockMatrix; + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + // copying a local jacobian is not a good idea - BoxLocalJacobian(const BoxLocalJacobian &); + ImplicitLocalJacobian(const ImplicitLocalJacobian &); public: - BoxLocalJacobian() + ImplicitLocalJacobian() { numericDifferenceMethod_ = GET_PARAM_FROM_GROUP(TypeTag, int, Implicit, NumericDifferenceMethod); Valgrind::SetUndefined(problemPtr_); @@ -119,8 +120,16 @@ public: localResidual_.init(prob); // assume quadrilinears as elements with most vertices - A_.setSize(2<<dim, 2<<dim); - storageJacobian_.resize(2<<dim); + if (isBox) + { + A_.setSize(2<<dim, 2<<dim); + storageJacobian_.resize(2<<dim); + } + else + { + A_.setSize(1, 2<<dim); + storageJacobian_.resize(1); + } } /*! @@ -176,19 +185,28 @@ public: model_().updatePVWeights(element_(), curVolVars_); // calculate the local jacobian matrix - int numVertices = fvElemGeom_.numVertices; - ElementSolutionVector partialDeriv(numVertices); - PrimaryVariables storageDeriv; - for (int j = 0; j < numVertices; j++) { + int numRows, numCols; + if (isBox) + { + numRows = numCols = fvElemGeom_.numVertices; + } + else + { + numRows = 1; + numCols = fvElemGeom_.numNeighbors; + } + ElementSolutionVector partialDeriv(numRows); + PrimaryVariables storageDeriv(0.0); + for (int col = 0; col < numCols; col++) { for (int pvIdx = 0; pvIdx < numEq; pvIdx++) { asImp_().evalPartialDerivative_(partialDeriv, storageDeriv, - j, + col, pvIdx); // update the local stiffness matrix with the current partial // derivatives - updateLocalJacobian_(j, + updateLocalJacobian_(col, pvIdx, partialDeriv, storageDeriv); @@ -328,10 +346,9 @@ protected: */ void reset_() { - int n = element_().template count<dim>(); - for (int i = 0; i < n; ++ i) { + for (int i = 0; i < A_.N(); ++ i) { storageJacobian_[i] = 0.0; - for (int j = 0; j < n; ++ j) { + for (int j = 0; j < A_.M(); ++ j) { A_[i][j] = 0.0; } } @@ -374,26 +391,37 @@ protected: * \param partialDeriv The vector storing the partial derivatives of all * equations * \param storageDeriv the mass matrix contributions - * \param scvIdx The sub-control volume index of the current - * finite element for which the partial derivative - * ought to be calculated - * \param pvIdx The index of the primary variable at the scvIdx' - * sub-control volume of the current finite element - * for which the partial derivative ought to be - * calculated + * \param col The block column index of the degree of freedom + * for which the partial derivative is calculated. + * Box: a sub-control volume index. + * Cell centered: a neighbor index. + * \param pvIdx The index of the primary variable + * for which the partial derivative is calculated */ void evalPartialDerivative_(ElementSolutionVector &partialDeriv, PrimaryVariables &storageDeriv, - const int scvIdx, + const int col, const int pvIdx) { - int globalIdx = vertexMapper_().map(element_(), scvIdx, dim); + int globalIdx; + FVElementGeometry neighborFVGeom; + ElementPointer neighbor(element_()); + if (isBox) + { + globalIdx = vertexMapper_().map(element_(), col, dim); + } + else + { + neighbor = fvElemGeom_.neighbors[col]; + neighborFVGeom.updateInner(*neighbor); + globalIdx = problemPtr_->elementMapper().map(*neighbor); + } PrimaryVariables priVars(model_().curSol()[globalIdx]); - VolumeVariables origVolVars(curVolVars_[scvIdx]); + VolumeVariables origVolVars(curVolVars_[col]); - curVolVars_[scvIdx].setEvalPoint(&origVolVars); - Scalar eps = asImp_().numericEpsilon(scvIdx, pvIdx); + curVolVars_[col].setEvalPoint(&origVolVars); + Scalar eps = asImp_().numericEpsilon(col, pvIdx); Scalar delta = 0; if (numericDifferenceMethod_ >= 0) { @@ -405,12 +433,21 @@ protected: delta += eps; // calculate the residual - curVolVars_[scvIdx].update(priVars, - problem_(), - element_(), - fvElemGeom_, - scvIdx, - false); + if (isBox) + curVolVars_[col].update(priVars, + problem_(), + element_(), + fvElemGeom_, + col, + false); + else + curVolVars_[col].update(priVars, + problem_(), + *neighbor, + neighborFVGeom, + /*scvIdx=*/0, + false); + localResidual().eval(element_(), fvElemGeom_, prevVolVars_, @@ -419,14 +456,15 @@ protected: // store the residual and the storage term partialDeriv = localResidual().residual(); - storageDeriv = localResidual().storageTerm()[scvIdx]; + if (isBox || col == 0) + storageDeriv = localResidual().storageTerm()[col]; } else { // we are using backward differences, i.e. we don't need // to calculate f(x + \epsilon) and we can recycle the // (already calculated) residual f(x) partialDeriv = residual_; - storageDeriv = storageTerm_[scvIdx]; + storageDeriv = storageTerm_[col]; } @@ -439,26 +477,37 @@ protected: delta += eps; // calculate residual again - curVolVars_[scvIdx].update(priVars, - problem_(), - element_(), - fvElemGeom_, - scvIdx, - false); + if (isBox) + curVolVars_[col].update(priVars, + problem_(), + element_(), + fvElemGeom_, + col, + false); + else + curVolVars_[col].update(priVars, + problem_(), + *neighbor, + neighborFVGeom, + /*scvIdx=*/0, + false); + localResidual().eval(element_(), fvElemGeom_, prevVolVars_, curVolVars_, bcTypes_); partialDeriv -= localResidual().residual(); - storageDeriv -= localResidual().storageTerm()[scvIdx]; + if (isBox || col == 0) + storageDeriv -= localResidual().storageTerm()[col]; } else { // we are using forward differences, i.e. we don't need to // calculate f(x - \epsilon) and we can recycle the // (already calculated) residual f(x) partialDeriv -= residual_; - storageDeriv -= storageTerm_[scvIdx]; + if (isBox || col == 0) + storageDeriv -= storageTerm_[col]; } // divide difference in residuals by the magnitude of the @@ -467,7 +516,7 @@ protected: storageDeriv /= delta; // restore the original state of the element's volume variables - curVolVars_[scvIdx] = origVolVars; + curVolVars_[col] = origVolVars; #if HAVE_VALGRIND for (unsigned i = 0; i < partialDeriv.size(); ++i) @@ -478,29 +527,32 @@ protected: /*! * \brief Updates the current local Jacobian matrix with the * partial derivatives of all equations in regard to the - * primary variable 'pvIdx' at vertex 'scvIdx' . + * primary variable 'pvIdx' at dof 'col' . */ - void updateLocalJacobian_(const int scvIdx, + void updateLocalJacobian_(const int col, const int pvIdx, const ElementSolutionVector &partialDeriv, const PrimaryVariables &storageDeriv) { // store the derivative of the storage term - for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - storageJacobian_[scvIdx][eqIdx][pvIdx] = storageDeriv[eqIdx]; + if (isBox || col == 0) + { + for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { + storageJacobian_[col][eqIdx][pvIdx] = storageDeriv[eqIdx]; + } } - for (int i = 0; i < fvElemGeom_.numVertices; i++) + for (int i = 0; i < fvElemGeom_.numSCV; i++) { // Green vertices are not to be changed! - if (jacAsm_().vertexColor(element_(), i) != Green) { + if (!isBox || jacAsm_().vertexColor(element_(), i) != Green) { for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - // A[i][scvIdx][eqIdx][pvIdx] is the rate of change of - // the residual of equation 'eqIdx' at vertex 'i' - // depending on the primary variable 'pvIdx' at vertex - // 'scvIdx'. - this->A_[i][scvIdx][eqIdx][pvIdx] = partialDeriv[i][eqIdx]; - Valgrind::CheckDefined(this->A_[i][scvIdx][eqIdx][pvIdx]); + // A[i][col][eqIdx][pvIdx] is the rate of change of + // the residual of equation 'eqIdx' at dof 'i' + // depending on the primary variable 'pvIdx' at dof + // 'col'. + this->A_[i][col][eqIdx][pvIdx] = partialDeriv[i][eqIdx]; + Valgrind::CheckDefined(this->A_[i][col][eqIdx][pvIdx]); } } } diff --git a/dumux/implicit/common/implicitlocalresidual.hh b/dumux/implicit/common/implicitlocalresidual.hh index 53eaa0bf554990078effe06e67ccab58387bf4e9..f020e8bbd1a32fd1a387bc4cfda69a1a7a56a0fd 100644 --- a/dumux/implicit/common/implicitlocalresidual.hh +++ b/dumux/implicit/common/implicitlocalresidual.hh @@ -20,8 +20,8 @@ * \file * \brief Calculates the residual of models based on the box scheme element-wise. */ -#ifndef DUMUX_BOX_LOCAL_RESIDUAL_HH -#define DUMUX_BOX_LOCAL_RESIDUAL_HH +#ifndef DUMUX_IMPLICIT_LOCAL_RESIDUAL_HH +#define DUMUX_IMPLICIT_LOCAL_RESIDUAL_HH #include <dune/istl/matrix.hh> #include <dune/grid/common/geometry.hh> @@ -33,15 +33,15 @@ namespace Dumux { /*! - * \ingroup BoxModel - * \ingroup BoxLocalResidual + * \ingroup ImplicitModel + * \ingroup ImplicitLocalResidual * \brief Element-wise calculation of the residual matrix for models - * based on the box scheme. + * using a fully implicit discretization. * * \todo Please doc me more! */ template<class TypeTag> -class BoxLocalResidual +class ImplicitLocalResidual { private: typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; @@ -49,22 +49,10 @@ private: typedef typename GET_PROP_TYPE(TypeTag, Model) Model; typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - enum { - numEq = GET_PROP_VALUE(TypeTag, NumEq), - dim = GridView::dimension - }; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GridView::template Codim<dim>::EntityPointer VertexPointer; typedef typename GridView::IntersectionIterator IntersectionIterator; - typedef typename GridView::Grid::ctype CoordScalar; - typedef typename Dune::GenericReferenceElements<CoordScalar, dim> ReferenceElements; - typedef typename Dune::GenericReferenceElement<CoordScalar, dim> ReferenceElement; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; @@ -73,13 +61,13 @@ private: typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; // copying the local residual class is not a good idea - BoxLocalResidual(const BoxLocalResidual &); + ImplicitLocalResidual(const ImplicitLocalResidual &); public: - BoxLocalResidual() + ImplicitLocalResidual() { } - ~BoxLocalResidual() + ~ImplicitLocalResidual() { } /*! @@ -190,7 +178,7 @@ public: ElementBoundaryTypes bcTypes; bcTypes.update(problem_(), element, fvGeometry_()); - residual_.resize(fvGeometry_().numVertices); + residual_.resize(fvGeometry_().numSCV); residual_ = 0; bcTypesPtr_ = &bcTypes; @@ -225,7 +213,7 @@ public: Valgrind::CheckDefined(curVolVars); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry.numVertices; i++) { + for (int i = 0; i < prevVolVars.size(); i++) { prevVolVars[i].checkDefined(); curVolVars[i].checkDefined(); } @@ -238,9 +226,9 @@ public: curVolVarsPtr_ = &curVolVars; // resize the vectors for all terms - int numVerts = fvGeometry_().numVertices; - residual_.resize(numVerts); - storageTerm_.resize(numVerts); + int numSCV = fvGeometry_().numSCV; + residual_.resize(numSCV); + storageTerm_.resize(numSCV); residual_ = 0.0; storageTerm_ = 0.0; @@ -248,14 +236,14 @@ public: asImp_().evalFluxes_(); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) + for (int i=0; i < fvGeometry_().numSCV; i++) Valgrind::CheckDefined(residual_[i]); #endif // HAVE_VALGRIND asImp_().evalVolumeTerms_(); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) { + for (int i=0; i < fvGeometry_().numSCV; i++) { Valgrind::CheckDefined(residual_[i]); } #endif // HAVE_VALGRIND @@ -264,7 +252,7 @@ public: asImp_().evalBoundary_(); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) + for (int i=0; i < fvGeometry_().numSCV; i++) Valgrind::CheckDefined(residual_[i]); #endif // HAVE_VALGRIND } @@ -322,7 +310,7 @@ protected: if (bcTypes_().hasNeumann() || bcTypes_().hasOutflow()) asImp_().evalBoundaryFluxes_(); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeometry_().numVertices; i++) + for (int i=0; i < fvGeometry_().numSCV; i++) Valgrind::CheckDefined(residual_[i]); #endif // HAVE_VALGRIND @@ -330,209 +318,18 @@ protected: asImp_().evalDirichlet_(); } - /*! - * \brief Set the values of the Dirichlet boundary control volumes - * of the current element. - */ - void evalDirichlet_() - { - PrimaryVariables dirichletValues(0); - for (int scvIdx = 0; scvIdx < fvGeometry_().numVertices; ++scvIdx) { - const BoundaryTypes &bcTypes = bcTypes_(scvIdx); - - if (bcTypes.hasDirichlet()) { - // ask the problem for the dirichlet values - const VertexPointer vPtr = element_().template subEntity<dim>(scvIdx); - Valgrind::SetUndefined(dirichletValues); - asImp_().problem_().dirichlet(dirichletValues, *vPtr); - - // set the dirichlet conditions - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - if (bcTypes.isDirichlet(eqIdx)) { - int pvIdx = bcTypes.eqToDirichletIndex(eqIdx); - assert(0 <= pvIdx && pvIdx < numEq); - Valgrind::CheckDefined(dirichletValues[pvIdx]); - - residual_[scvIdx][eqIdx] = - curPriVar_(scvIdx, pvIdx) - dirichletValues[pvIdx]; - - storageTerm_[scvIdx][eqIdx] = 0.0; - } - } - } - } - } - - /*! - * \brief Add all Neumann and outflow boundary conditions to the local - * residual. - */ - void evalBoundaryFluxes_() - { - Dune::GeometryType geoType = element_().geometry().type(); - const ReferenceElement &refElement = ReferenceElements::general(geoType); - - IntersectionIterator isIt = gridView_().ibegin(element_()); - const IntersectionIterator &endIt = gridView_().iend(element_()); - for (; isIt != endIt; ++isIt) - { - // handle only faces on the boundary - if (isIt->boundary()) { - // Assemble the boundary for all vertices of the current - // face - int faceIdx = isIt->indexInInside(); - int numFaceVerts = refElement.size(faceIdx, 1, dim); - for (int faceVertIdx = 0; - faceVertIdx < numFaceVerts; - ++faceVertIdx) - { - int scvIdx = refElement.subEntity(faceIdx, - 1, - faceVertIdx, - dim); - - int boundaryFaceIdx = - fvGeometry_().boundaryFaceIndex(faceIdx, faceVertIdx); - - // add the residual of all vertices of the boundary - // segment - asImp_().evalNeumannSegment_(isIt, - scvIdx, - boundaryFaceIdx); - // evaluate the outflow conditions at the boundary face - // ATTENTION: This is so far a beta version that is only for the 2p2c and 2p2cni model - // available and not thoroughly tested. - asImp_().evalOutflowSegment_(isIt, - scvIdx, - boundaryFaceIdx); - } - } - } - } - - /*! - * \brief Add Neumann boundary conditions for a single sub-control - * volume face to the local residual. - */ - void evalNeumannSegment_(const IntersectionIterator &isIt, - const int scvIdx, - const int boundaryFaceIdx) - { - // temporary vector to store the neumann boundary fluxes - PrimaryVariables neumannFlux(0.0); - const BoundaryTypes &bcTypes = bcTypes_(scvIdx); - - // deal with neumann boundaries - if (bcTypes.hasNeumann()) { - Valgrind::SetUndefined(neumannFlux); - problem_().boxSDNeumann(neumannFlux, - element_(), - fvGeometry_(), - *isIt, - scvIdx, - boundaryFaceIdx, - curVolVars_()); - neumannFlux *= - fvGeometry_().boundaryFace[boundaryFaceIdx].area - * curVolVars_(scvIdx).extrusionFactor(); - Valgrind::CheckDefined(neumannFlux); - - // set the neumann conditions - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - if (!bcTypes.isNeumann(eqIdx)) - continue; - residual_[scvIdx][eqIdx] += neumannFlux[eqIdx]; - } - } - } - - /*! - * \brief Add outflow boundary conditions for a single sub-control - * volume face to the local residual. - * - * \param isIt The intersection iterator of current element - * \param scvIdx The index of the considered face of the sub-control volume - * \param boundaryFaceIdx The index of the considered boundary face of the sub control volume - */ - void evalOutflowSegment_(const IntersectionIterator &isIt, - const int scvIdx, - const int boundaryFaceIdx) - { - const BoundaryTypes &bcTypes = this->bcTypes_(scvIdx); - // deal with outflow boundaries - if (bcTypes.hasOutflow()) - { - //calculate outflow fluxes - PrimaryVariables values(0.0); - asImp_().computeFlux(values, boundaryFaceIdx, true); - Valgrind::CheckDefined(values); - - for (int equationIdx = 0; equationIdx < numEq; ++equationIdx) - { - if (!bcTypes.isOutflow(equationIdx) ) - continue; - // deduce outflow - this->residual_[scvIdx][equationIdx] += values[equationIdx]; - } - } - } - - /*! - * \brief Add the flux terms to the local residual of all - * sub-control volumes of the current element. - */ - void evalFluxes_() - { - // calculate the mass flux over the faces and subtract - // it from the local rates - for (int scvfIdx = 0; scvfIdx < fvGeometry_().numEdges; scvfIdx++) - { - int i = fvGeometry_().subContVolFace[scvfIdx].i; - int j = fvGeometry_().subContVolFace[scvfIdx].j; - - PrimaryVariables flux; - - Valgrind::SetUndefined(flux); - asImp_().computeFlux(flux, scvfIdx); - Valgrind::CheckDefined(flux); - - Scalar extrusionFactor = - (curVolVars_(i).extrusionFactor() - + curVolVars_(j).extrusionFactor()) - / 2; - flux *= extrusionFactor; - - // The balance equation for a finite volume is: - // - // dStorage/dt = Flux + Source - // - // where the 'Flux' and the 'Source' terms represent the - // mass per second which _ENTER_ the finite - // volume. Re-arranging this, we get - // - // dStorage/dt - Source - Flux = 0 - // - // Since the flux calculated by computeFlux() goes _OUT_ - // of sub-control volume i and _INTO_ sub-control volume - // j, we need to add the flux to finite volume i and - // subtract it from finite volume j - residual_[i] += flux; - residual_[j] -= flux; - } - } - /*! * \brief Set the local residual to the storage terms of all * sub-control volumes of the current element. */ void evalStorage_() { - storageTerm_.resize(fvGeometry_().numVertices); + storageTerm_.resize(fvGeometry_().numSCV); storageTerm_ = 0; // calculate the amount of conservation each quantity inside // all sub control volumes - for (int scvIdx = 0; scvIdx < fvGeometry_().numVertices; scvIdx++) { + for (int scvIdx = 0; scvIdx < fvGeometry_().numSCV; scvIdx++) { Valgrind::SetUndefined(storageTerm_[scvIdx]); asImp_().computeStorage(storageTerm_[scvIdx], scvIdx, /*isOldSol=*/false); storageTerm_[scvIdx] *= @@ -550,7 +347,7 @@ protected: void evalVolumeTerms_() { // evaluate the volume terms (storage + source terms) - for (int scvIdx = 0; scvIdx < fvGeometry_().numVertices; scvIdx++) + for (int scvIdx = 0; scvIdx < fvGeometry_().numSCV; scvIdx++) { Scalar extrusionFactor = curVolVars_(scvIdx).extrusionFactor(); @@ -602,12 +399,6 @@ protected: const Model &model_() const { return problem_().model(); }; - /*! - * \brief Returns a reference to the vertex mapper. - */ - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); }; - /*! * \brief Returns a reference to the grid view. */ diff --git a/dumux/implicit/common/implicitporousmediaproblem.hh b/dumux/implicit/common/implicitporousmediaproblem.hh index 0fbde7b6edbbef7299712e892a35a8ce6c6128b3..fab231a7b6486b762d62ef2c0ca6cfd9410c0872 100644 --- a/dumux/implicit/common/implicitporousmediaproblem.hh +++ b/dumux/implicit/common/implicitporousmediaproblem.hh @@ -1,7 +1,6 @@ // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /***************************************************************************** - * 2012 by Bernd Flemisch * * See the file COPYING for full copying permissions. * * * * This program is free software: you can redistribute it and/or modify * diff --git a/dumux/implicit/common/implicitpropertydefaults.hh b/dumux/implicit/common/implicitpropertydefaults.hh index 69bdeb04a1475ade88b8acd1ee26cb210073dc7e..032ab4faa5b98cfe0ae9cad92fc650a2338cf58d 100644 --- a/dumux/implicit/common/implicitpropertydefaults.hh +++ b/dumux/implicit/common/implicitpropertydefaults.hh @@ -33,6 +33,7 @@ #include <dumux/common/timemanager.hh> #include "implicitproperties.hh" +#include "implicitlocaljacobian.hh" #include "implicitvolumevariables.hh" namespace Dumux { @@ -73,7 +74,10 @@ SET_TYPE_PROP(ImplicitBase, Dune::MCMGElementLayout>); //! The volume variable class, to be overloaded by the model -SET_TYPE_PROP(BoxModel, VolumeVariables, Dumux::ImplicitVolumeVariables<TypeTag>); +SET_TYPE_PROP(ImplicitBase, VolumeVariables, Dumux::ImplicitVolumeVariables<TypeTag>); + +//! The local jacobian operator for the box scheme +SET_TYPE_PROP(ImplicitBase, LocalJacobian, Dumux::ImplicitLocalJacobian<TypeTag>); //! The type of a solution for the whole grid at a fixed time SET_TYPE_PROP(ImplicitBase,