diff --git a/dumux/geomechanics/el1p2c/el1p2celementvolumevariables.hh b/dumux/geomechanics/el1p2c/el1p2celementvolumevariables.hh index 5d231b8adf9821b8834f8393b1e9d98de6b58d98..aa9f9ce86b529c886f8e0f5e34a6bf8269c5f4cf 100644 --- a/dumux/geomechanics/el1p2c/el1p2celementvolumevariables.hh +++ b/dumux/geomechanics/el1p2c/el1p2celementvolumevariables.hh @@ -1,145 +1,8 @@ -// -*- 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 Volume variables gathered on an element - */ -#ifndef DUMUX_BOX_EL1P2C_ELEMENT_VOLUME_VARIABLES_HH -#define DUMUX_BOX_EL1P2C_ELEMENT_VOLUME_VARIABLES_HH +#ifndef DUMUX_BOX_EL1P2C_ELEMENT_VOLUME_VARIABLES_HH_OLD +#define DUMUX_BOX_EL1P2C_ELEMENT_VOLUME_VARIABLES_HH_OLD -#include <dumux/implicit/box/properties.hh> -#include <dumux/implicit/box/elementvolumevariables.hh> +#warning this header is deprecated, use dumux/geomechanics/el1p2c/elementvolumevariables.hh instead -namespace Dumux -{ - -/*! - * \ingroup ElOnePTwoCBoxModel - * - * \brief This class stores an array of VolumeVariables objects, one - * volume variables object for each of the element's vertices - */ -template<class TypeTag> -class ElOnePTwoCElementVolumeVariables : public BoxElementVolumeVariables<TypeTag> -{ - typedef BoxElementVolumeVariables<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - enum { dim = GridView::dimension }; - - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - -public: - /*! - * \brief The constructor. - */ - ElOnePTwoCElementVolumeVariables() - { } - - /*! - * \brief Construct the volume variables for all vertices of an element. - * - * \param problem The problem which needs to be simulated. - * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated - * \param fvGeometry The finite volume geometry of the element - * \param oldSol Tells whether the model's previous or current solution should be used. - * - * This class is required for the update of the effective porosity values at the - * vertices since it is a function of the divergence of the solid displacement - * at the integration points - */ - void update(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - bool oldSol) - { - ParentType::update(problem, element, fvGeometry, oldSol); - this->updateEffPorosity(problem, element, fvGeometry); - - }; - - /*! - * \brief Update the effective porosities and the volumetric strain divU for all vertices of an element. - * - * \param problem The problem which needs to be simulated. - * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated - * \param fvGeometry The finite volume geometry of the element - * - * This function is required for the update of the effective porosity / divU values at the - * vertices. - * - * During the partial derivative calculation, changes of the solid displacement - * at vertex i can affect effective porosities / divU of all element vertices. - * To correctly update the effective porosities / divU of all element vertices - * an iteration over all scv faces is required. - * The remaining volvars are only updated for the vertex whose primary variable - * is changed for the derivative calculation. - */ - void updateEffPorosity(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry) - { - // we assert that the i-th shape function is - // associated to the i-th vert of the element. - int numScv = element.subEntities(dim); - - // number of faces which contribute to the porosity value in the sub-control volume - std::vector<double> numContributingFaces; - numContributingFaces.resize(numScv); - - for (int scvIdx = 0; scvIdx < numScv; scvIdx++) { - (*this)[scvIdx].effPorosity = 0.0; - (*this)[scvIdx].divU = 0.0; - numContributingFaces[scvIdx] = 0.0; - } - for (int fIdx = 0; fIdx < fvGeometry.numScvf; fIdx++) - { - // evaluate the gradients at the IPs for each subcontrol volume face - FluxVariables fluxVars(problem, - element, - fvGeometry, - fIdx, - *this); - - numContributingFaces[fluxVars.face().i] += 1; - numContributingFaces[fluxVars.face().j] += 1; - - // average value for the effective porosity - (*this)[fluxVars.face().i].effPorosity += fluxVars.effPorosity(); - (*this)[fluxVars.face().j].effPorosity += fluxVars.effPorosity(); - // average value for the volumetric strain - (*this)[fluxVars.face().i].divU += fluxVars.divU(); - (*this)[fluxVars.face().j].divU += fluxVars.divU(); - - } - for (int scvIdx = 0; scvIdx < numScv; scvIdx++) { - (*this)[scvIdx].effPorosity /= numContributingFaces[scvIdx]; - (*this)[scvIdx].divU /= numContributingFaces[scvIdx]; - } - }; - - -}; - -} // namespace Dumux +#include <dumux/geomechanics/el1p2c/elementvolumevariables.hh> #endif diff --git a/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh b/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh index 29c4ac9a35878fe9f277151d462a2f4c05205199..6ed09870c80bce535d5b3d1aacffaa0f8aa6df80 100644 --- a/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh +++ b/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh @@ -1,321 +1,8 @@ -// -*- 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 This file contains the calculation of all the fluxes over the surface of the - * finite volume that make up the volume, the mass and the momentum balance - * for the one-phase two-component linear-elastic model. - * - * This means pressure, concentration and solid-displacement gradients, phase densities at - * the integration point, etc. - * - * This class inherits from the one-phase two-component model FluxVariables and from the - * linear elasticity model FluxVariables - */ -#ifndef DUMUX_ELASTIC1P2C_FLUX_VARIABLES_HH -#define DUMUX_ELASTIC1P2C_FLUX_VARIABLES_HH +#ifndef DUMUX_ELASTIC1P2C_FLUX_VARIABLES_HH_OLD +#define DUMUX_ELASTIC1P2C_FLUX_VARIABLES_HH_OLD -#include <dumux/geomechanics/elastic/elasticfluxvariables.hh> -#include <dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh> +#warning this header is deprecated, use dumux/geomechanics/el1p2c/fluxvariables.hh instead -namespace Dumux -{ -/*! - * \ingroup ElOnePTwoCBoxModel - * \ingroup ImplicitFluxVariables - * \brief This template class contains the data which is required to - * calculate the fluxes over the surface of the - * finite volume that make up the volume, the mass and the momentum balance - * for the one-phase two-component linear-elastic model. - * - * This means pressure, concentration and solid-displacement gradients, phase densities at - * the integration point, etc. - * - */ - template<class TypeTag> - class ElOnePTwoCFluxVariables: public ElasticFluxVariablesBase<TypeTag> , - public OnePTwoCFluxVariables<TypeTag> - { - typedef ElasticFluxVariablesBase<TypeTag> ElasticBase; - typedef OnePTwoCFluxVariables<TypeTag> OnePTwoCBase; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel) EffectiveDiffusivityModel; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - enum - { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld - }; - - typedef typename GridView::ctype CoordScalar; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - typedef Dune::FieldVector<CoordScalar, dim> DimVector; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; - - public: - /* - * \brief The constructor - * - * \param problem The problem - * \param element The finite element - * \param fvGeometry The finite-volume geometry in the fully implicit scheme - * \param fIdx The local index of the SCV (sub-control-volume) face - * \param elemVolVars The volume variables of the current element - * \param onBoundary A boolean variable to specify whether the flux variables - * are calculated for interior SCV faces or boundary faces, default=false - */ - ElOnePTwoCFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : ElasticBase(problem, element, fvGeometry, fIdx, elemVolVars), - OnePTwoCBase(problem, element, fvGeometry, fIdx, elemVolVars), - fvGeometry_(fvGeometry), faceIdx_(fIdx), onBoundary_(onBoundary) - { - dU_ = Scalar(0); - dGradP_ = Scalar(0); - porosity_ = 0; - effPorosity_ = 0; - pressure_ = 0; - timeDerivUNormal_ = 0; - - elOnePTwoCGradients_(problem, element, elemVolVars); - calculateEffectiveValues_(problem, element, elemVolVars); - calculateDiffCoeffPM_(problem, element, elemVolVars); - calculateDDt_(problem, element, elemVolVars); - - } - ; - - public: - /*! - * \brief Return porosity [-] at the integration point. - */ - Scalar porosity() const - { - return porosity_; - } - - /*! - * \brief Return effective porosity [-] at the integration point. - */ - Scalar effPorosity() const - { - return effPorosity_; - } - - /*! - * \brief Return pressure [Pa] at the integration - * point. - */ - Scalar pressure() const - { - return pressure_; - } - - /*! - * \brief Return change of pressure gradient with time [Pa/m] at - * integration point. - */ - Scalar dGradP(int dimIdx) const - { - return dGradP_[dimIdx]; - } - - /*! - * \brief Return gradient of time derivative of pressure [Pa]. - */ - Scalar timeDerivGradPNormal() const - { - return timeDerivGradPNormal_; - } - - /*! - * \brief Return change of u [m] with time at integration point - * point. - */ - Scalar dU(int dimIdx) const - { - return dU_[dimIdx]; - } - - /*! - * \brief Return time derivative of u [m/s] in normal direction at integration point - */ - Scalar timeDerivUNormal() const - { - return timeDerivUNormal_; - } - - /*! - * \brief Return porous medium diffusion coefficient [m^2] - */ - Scalar diffCoeffPM() const - { - return diffCoeffPM_; - } - - const SCVFace &face() const - { - return fvGeometry_.subContVolFace[faceIdx_]; - } - - protected: - /*! - * \brief Calculation of the solid displacement and pressure gradients. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void elOnePTwoCGradients_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - // calculate gradients - GlobalPosition tmp(0.0); - for (int idx = 0; idx < fvGeometry_.numScv; idx++) // loop over adjacent vertices - { - // FE gradient at vertex idx - const DimVector &feGrad = face().grad[idx]; - - // the gradient of the temporal pressure change (needed for stabilization term) - tmp = feGrad; - tmp *= elemVolVars[idx].dPressure(); - dGradP_ += tmp; - - // average the pressure at integration point - pressure_ += elemVolVars[idx].pressure() - * face().shapeValue[idx]; - // average temporal displacement change at integration point (for calculation of solid displacement velocity) - for (int i = 0; i < dim; ++i) - dU_[i] += elemVolVars[idx].dU(i) - * face().shapeValue[idx]; - // average porosity at integration point - porosity_ += elemVolVars[idx].porosity() - * face().shapeValue[idx]; - } - } - - /*! - * \brief Calculation of the effective porosity. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateEffectiveValues_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - - // the effective porosity is calculated as a function of solid displacement and initial porosity - // according to Han & Dusseault (2003) - - // calculate effective porosity as a function of solid displacement and initial porosity - effPorosity_ = (porosity_ + this->divU()) - / (1 + this->divU()); - } - - /*! - * \brief Calculation of the effective porous media diffusion coefficient. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateDiffCoeffPM_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - const VolumeVariables &volVarsI = elemVolVars[face().i]; - const VolumeVariables &volVarsJ = elemVolVars[face().j]; - - const Scalar diffCoeffI = - EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), - /*sat=*/1.0, - volVarsI.diffCoeff()); - - const Scalar diffCoeffJ = - EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), - /*sat=*/1.0, - volVarsJ.diffCoeff()); - - diffCoeffPM_ = harmonicMean(diffCoeffI, diffCoeffJ); - } - - /*! - * \brief Calculation of the time derivative of solid displacement and pressure gradient - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateDDt_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - Scalar dt= problem.timeManager().timeStepSize(); - DimVector tmp(0.0); - - //time derivative of solid displacement times normal vector - for (int i = 0; i < dim; ++i) - tmp[i] = dU_[i] / dt; - timeDerivUNormal_ = tmp * face().normal; - //time derivative of pressure gradient times normal vector - for (int i = 0; i < dim; ++i) - tmp[i] = dGradP_[i] / dt; - timeDerivGradPNormal_ = tmp * face().normal; - } - - const FVElementGeometry &fvGeometry_; - int faceIdx_; - const bool onBoundary_; - - //! change of solid displacement with time at integration point - GlobalPosition dU_; - //! change of pressure gradient with time at integration point - GlobalPosition dGradP_; - //! porosity at integration point - Scalar porosity_; - //! effective porosity at integration point - Scalar effPorosity_; - //! pressure at integration point - Scalar pressure_; - //! time derivative of solid displacement times normal vector at integration point - Scalar timeDerivUNormal_; - //! time derivative of pressure gradient times normal vector at integration point - Scalar timeDerivGradPNormal_; - //! Parameters - Scalar diffCoeffPM_; - }; - -} // end namespace +#include <dumux/geomechanics/el1p2c/fluxvariables.hh> #endif diff --git a/dumux/geomechanics/el1p2c/el1p2cindices.hh b/dumux/geomechanics/el1p2c/el1p2cindices.hh index 25346a73ee853decbd7dd0f33869da79f9b1a93e..aad2de0ddf292ca0a63eb910529c504066a06788 100644 --- a/dumux/geomechanics/el1p2c/el1p2cindices.hh +++ b/dumux/geomechanics/el1p2c/el1p2cindices.hh @@ -1,54 +1,8 @@ -// -*- 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 Defines the primary variable and equation indices used by - * the one-phase two-component linear elasticity model. - */ +#ifndef DUMUX_ELASTIC1P2C_INDICES_HH_OLD +#define DUMUX_ELASTIC1P2C_INDICES_HH_OLD -#ifndef DUMUX_ELASTIC1P2C_INDICES_HH -#define DUMUX_ELASTIC1P2C_INDICES_HH +#warning this header is deprecated, use dumux/geomechanics/el1p2c/indices.hh instead -#include <dumux/geomechanics/elastic/elasticindices.hh> -#include <dumux/porousmediumflow/1p2c/implicit/indices.hh> - -namespace Dumux -{ -// \{ - -/*! - * \ingroup ElOnePTwoCBoxModel - * \ingroup ImplicitIndices - * \brief The indices for the one-phase two-component linear elasticity model. - * - * This class inherits from the OnePTwoCIndices and from the ElasticIndices - */ -template <class TypeTag> -// PVOffset is set to 0 for the OnePTwoCIndices and to 2 for the ElasticIndices since -// the first two primary variables are the primary variables of the one-phase two-component -// model followed by the primary variables of the elastic model -class ElOnePTwoCIndices : public OnePTwoCIndices<TypeTag, 0>, public ElasticIndices<2> -{ -}; - -} // namespace Dumux +#include <dumux/geomechanics/el1p2c/indices.hh> #endif - diff --git a/dumux/geomechanics/el1p2c/el1p2clocaljacobian.hh b/dumux/geomechanics/el1p2c/el1p2clocaljacobian.hh index 4184d8cd4aa2dc93c0fb74f75241a7952d40e224..816459cc8bd44dd3679cfa4ed8be644769f1d220 100644 --- a/dumux/geomechanics/el1p2c/el1p2clocaljacobian.hh +++ b/dumux/geomechanics/el1p2c/el1p2clocaljacobian.hh @@ -1,258 +1,8 @@ -// -*- 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 Calculates the partial derivatives of the local residual for the Jacobian of the - * one-phase two-component linear elasticity model. - */ -#ifndef DUMUX_EL1P2C_LOCAL_JACOBIAN_HH -#define DUMUX_EL1P2C_LOCAL_JACOBIAN_HH +#ifndef DUMUX_EL1P2C_LOCAL_JACOBIAN_HH_OLD +#define DUMUX_EL1P2C_LOCAL_JACOBIAN_HH_OLD -#include <dumux/implicit/localjacobian.hh> +#warning this header is deprecated, use dumux/geomechanics/el1p2c/localjacobian.hh instead -namespace Dumux -{ -/*! - * \ingroup ElOnePTwoCBoxModel - * \brief Calculates the partial derivatives of the local residual for the Jacobian - * - * Except for the evalPartialDerivatives function all functions are taken from the - * base class ImplicitLocalJacobian - */ -template<class TypeTag> -class ElOnePTwoCLocalJacobian : public ImplicitLocalJacobian<TypeTag> -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum { - dim = GridView::dimension, - }; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - 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, Scalar) Scalar; - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - - // copying a local jacobian is not a good idea - ElOnePTwoCLocalJacobian(const ElOnePTwoCLocalJacobian &); - -public: - ElOnePTwoCLocalJacobian() - {} - - /*! - * \brief Compute the partial derivatives to a primary variable at - * an degree of freedom. - * - * This method is overwritten here since this model requires a call of the model specific - * elementvolumevariables which updates the effective porosities correctly. - * - * 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 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 col, - const int pvIdx) - { - int dofIdxGlobal; - FVElementGeometry neighborFVGeom; - auto neighbor = this->element_(); - if (isBox) - { - dofIdxGlobal = this->vertexMapper_().subIndex(this->element_(), col, dim); - - } - else - { - neighbor = this->fvElemGeom_.neighbors[col]; - neighborFVGeom.updateInner(neighbor); - dofIdxGlobal = this->problemPtr_->elementMapper().index(neighbor); - - } - - PrimaryVariables priVars(this->model_().curSol()[dofIdxGlobal]); - VolumeVariables origVolVars(this->curVolVars_[col]); - - this->curVolVars_[col].setEvalPoint(&origVolVars); - Scalar eps = this->numericEpsilon(col, pvIdx); - Scalar delta = 0; - - if (this->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 - if (isBox){ - this->curVolVars_[col].update(priVars, - this->problem_(), - this->element_(), - this->fvElemGeom_, - col, - false); - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_); - } - else{ - this->curVolVars_[col].update(priVars, - this->problem_(), - neighbor, - neighborFVGeom, - /*scvIdx=*/0, - false); - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_); - } - - this->localResidual().eval(this->element_(), - this->fvElemGeom_, - this->prevVolVars_, - this->curVolVars_, - this->bcTypes_); - - // store the residual and the storage term - partialDeriv = this->localResidual().residual(); - if (isBox || col == 0) - storageDeriv = this->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 = this->residual_; - storageDeriv = this->storageTerm_[col]; - } - - - if (this->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 - if (isBox){ - this->curVolVars_[col].update(priVars, - this->problem_(), - this->element_(), - this->fvElemGeom_, - col, - false); - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_); - } - else{ - this->curVolVars_[col].update(priVars, - this->problem_(), - neighbor, - neighborFVGeom, - /*scvIdx=*/0, - false); - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_); - } - - this->localResidual().eval(this->element_(), - this->fvElemGeom_, - this->prevVolVars_, - this->curVolVars_, - this->bcTypes_); - partialDeriv -= this->localResidual().residual(); - if (isBox || col == 0) - storageDeriv -= this->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 -= this->residual_; - if (isBox || col == 0) - storageDeriv -= this->storageTerm_[col]; - } - - // 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 - this->curVolVars_[col] = origVolVars; - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_); - -#if HAVE_VALGRIND - for (unsigned i = 0; i < partialDeriv.size(); ++i) - Valgrind::CheckDefined(partialDeriv[i]); -#endif - } -}; -} +#include <dumux/geomechanics/el1p2c/localjacobian.hh> #endif diff --git a/dumux/geomechanics/el1p2c/el1p2clocalresidual.hh b/dumux/geomechanics/el1p2c/el1p2clocalresidual.hh index aeb4c2a7ec0e8d559de59e087483059b4177ed98..1fa9d64fbbffb7c407ebfb47d7b407dac0767f7f 100644 --- a/dumux/geomechanics/el1p2c/el1p2clocalresidual.hh +++ b/dumux/geomechanics/el1p2c/el1p2clocalresidual.hh @@ -1,387 +1,8 @@ -// -*- 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 Element-wise calculation the local Jacobian for the linear elastic, - * single-phase, two-component model in the fully implicit scheme. - */ -#ifndef DUMUX_ELASTIC1P2C_LOCAL_RESIDUAL_HH -#define DUMUX_ELASTIC1P2C_LOCAL_RESIDUAL_HH +#ifndef DUMUX_ELASTIC1P2C_LOCAL_RESIDUAL_HH_OLD +#define DUMUX_ELASTIC1P2C_LOCAL_RESIDUAL_HH_OLD -#include "el1p2cproperties.hh" +#warning this header is deprecated, use dumux/geomechanics/el1p2c/localresidual.hh instead -namespace Dumux -{ - /*! - * \ingroup ElOnePTwoCModel - * \ingroup ImplicitLocalResidual - * \brief Calculate the local Jacobian for a one-phase two-component - * flow in a linear-elastic porous medium. - * - * This class is used to fill the gaps in BoxLocalResidual for the - * one-phase two-component linear elasticity model. - */ - template<class TypeTag> - class ElOnePTwoCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) - { - protected: - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - enum { dim = GridView::dimension }; - typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - typedef Dune::FieldVector<Scalar, dim> DimVector; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum { - //phase index - phaseIdx = Indices::phaseIdx, - transportCompIdx = Indices::transportCompIdx - }; - // indices of the equations - enum { - conti0EqIdx = Indices::conti0EqIdx, - transportEqIdx = Indices::transportEqIdx - }; - - //! property that defines whether mole or mass fractions are used - static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); - - - public: - /*! - * \brief Constructor. Sets the upwind weight. - */ - ElOnePTwoCLocalResidual() - { - // retrieve the upwind weight for the mass conservation equations. Use the value - // specified via the property system as default, and overwrite - // it by the run-time parameter from the Dune::ParameterTree - upwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); - // retrieve the property which defines if the stabilization terms in the mass balance - // equations are switched on. Use the value specified via the property system as default, - // and overwrite it by the run-time parameter from the Dune::ParameterTree - withStabilization_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, WithStabilization); - }; - - /*! - * \brief Evaluate the amount of all conservation quantities - * (e.g. phase mass) within a finite volume. - * - * \param storage The mass of the component within the sub-control volume - * \param scvIdx The index of the considered face of the sub-control volume - * \param usePrevSol Evaluate function with solution of current or previous time step - */ - void computeStorage(PrimaryVariables &storage, int scvIdx, - bool usePrevSol) const - { - // if flag usePrevSol is set, the solution from the previous - // time step is used, otherwise the current solution is - // used. The secondary variables are used accordingly. This - // is required to compute the derivative of the storage term - // using the implicit euler method. - const ElementVolumeVariables &elemVolVars = usePrevSol ? this->prevVolVars_() : this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[scvIdx]; - - storage = 0; - // this model assumes incompressible fluids and solids only the bulk - // density i.e. the ratio of solid phase and pore fluid can vary - // storage term of continuity equation - storage[conti0EqIdx] += volVars.divU; - - if(useMoles) - { - // storage term of the transport equation - mole fractions - storage[transportEqIdx] += volVars.moleFraction(transportCompIdx) - * volVars.effPorosity; - } - else - { - //storage term of the transport equation - mass fractions - storage[transportEqIdx] += volVars.massFraction(transportCompIdx) - * volVars.effPorosity; - } - } - - /*! - * \brief Evaluate the mass flux over a face of a sub-control - * volume. - * - * \param flux The flux over the SCV (sub-control-volume) face for each component - * \param fIdx The index of the considered face of the sub control volume - * \param onBoundary A boolean variable to specify whether the flux variables - * are calculated for interior SCV faces or boundary faces, default=false - */ - void computeFlux(PrimaryVariables &flux, int fIdx, const bool onBoundary=false) const - { - flux = 0; - FluxVariables fluxVars(this->problem_(), - this->element_(), - this->fvGeometry_(), - fIdx, - this->curVolVars_()); - - this->computeAdvectiveFlux(flux, fluxVars); - this->computeDiffusiveFlux(flux, fluxVars); - this->computeStresses(flux, fluxVars, fIdx); - } - - /*! - * \brief Evaluates the advective mass flux of all phases over - * a face of a subcontrol volume. - * - * \param flux The advective flux over the sub-control-volume face for each component - * \param fluxVars The flux variables at the current SCV - */ - void computeAdvectiveFlux(PrimaryVariables &flux, - const FluxVariables &fluxVars) const - { - //////// - // advective fluxes of all components in all phases - //////// - - // data attached to upstream and the downstream vertices - // of the current phase - const VolumeVariables &up = - this->curVolVars_(fluxVars.upstreamIdx()); - const VolumeVariables &dn = - this->curVolVars_(fluxVars.downstreamIdx()); - - // calculate the stabilization term which helps in case of stability problems - // e.g. observed for small time steps (according to G.Aguilar, F.Gaspar, F.Lisbona - // and C.Rodrigo (2008)) - Scalar stabilizationTerm(0.0); - if(withStabilization_){ - // calculate distance h between nodes i and j - const auto geometry = this->element_().geometry(); - DimVector hVec = geometry.corner(fluxVars.face().j) - - geometry.corner(fluxVars.face().i); - Scalar h = hVec.two_norm(); - stabilizationTerm = (h * h) / - (4 * (fluxVars.lambda() - + 2 * fluxVars.mu())); - - stabilizationTerm *= fluxVars.timeDerivGradPNormal(); - } - - - // flux for mass balance of the solid-fluid mixture - // KmvpNormal is the Darcy velocity multiplied with the normal vector, - // calculated in 1p2cfluxvariables.hh - flux[conti0EqIdx] += - fluxVars.KmvpNormal() * - (( upwindWeight_)/up.viscosity() - + - ((1 - upwindWeight_)/dn.viscosity())); - - - // stabilization term - if(withStabilization_) - flux[conti0EqIdx] -= stabilizationTerm; - - if(useMoles) - { - // mass flux of the dissolved second component - massfraction - // advective flux of the component - flux[transportEqIdx] += - fluxVars.KmvpNormal() * - (( upwindWeight_)* up.moleFraction(transportCompIdx)/up.viscosity() - + - (1 - upwindWeight_)* dn.moleFraction(transportCompIdx)/dn.viscosity()); - - // flux of the dissolved second component due to solid displacement - flux[transportEqIdx] += - fluxVars.timeDerivUNormal() * - (( upwindWeight_)* up.moleFraction(transportCompIdx) - * up.effPorosity - + - (1 - upwindWeight_)*dn.moleFraction(transportCompIdx) - * up.effPorosity); - - // stabilization term - if(withStabilization_) - flux[transportEqIdx] -= - stabilizationTerm * - (( upwindWeight_)* up.moleFraction(transportCompIdx) - + - (1 - upwindWeight_)*dn.moleFraction(transportCompIdx)); - } - else - { - // mass flux of the dissolved second component - massfraction - // advective flux of the component - flux[transportEqIdx] += - fluxVars.KmvpNormal() * - (( upwindWeight_)* up.massFraction(transportCompIdx)/up.viscosity() - + - (1 - upwindWeight_)* dn.massFraction(transportCompIdx)/dn.viscosity()); - - // flux of the dissolved second component due to solid displacement - flux[transportEqIdx] += - fluxVars.timeDerivUNormal() * - (( upwindWeight_)* up.massFraction(transportCompIdx) - * up.effPorosity - + - (1 - upwindWeight_)*dn.massFraction(transportCompIdx) - * up.effPorosity); - - // stabilization term - if(withStabilization_) - flux[transportEqIdx] -= - stabilizationTerm * - (( upwindWeight_)* up.massFraction(transportCompIdx) - + - (1 - upwindWeight_)*dn.massFraction(transportCompIdx)); - } - } - - /*! - * \brief Adds the diffusive mass flux of all components over - * a face of a sub-control volume. - * - * \param flux The diffusive flux over the sub-control-volume face for each component - * \param fluxVars The flux variables at the current sub-control-volume face - */ - void computeDiffusiveFlux(PrimaryVariables &flux, - const FluxVariables &fluxVars) const - { - Scalar tmp(0); - - // diffusive flux of second component - if(useMoles) - { - // diffusive flux of the second component - mole fraction - tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); - tmp *= fluxVars.diffCoeffPM(); - - // dispersive flux of second component - mole fraction - DimVector normalDisp; - fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); - tmp -= (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); - - flux[transportEqIdx] += tmp; - } - else - { - // diffusive flux of the second component - mass fraction - tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); - tmp *= fluxVars.diffCoeffPM(); - - // dispersive flux of second component - mass fraction - DimVector normalDisp; - fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); - tmp -= (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); - - // convert it to a mass flux and add it - flux[transportEqIdx] += tmp * FluidSystem::molarMass(transportCompIdx); - } - } - - /*! - * \brief Evaluates the total stress induced by effective stresses and fluid - * pressure in the solid fluid mixture. - * \param stress The stress over the sub-control-volume face for each component - * \param fluxVars The variables at the current sub-control-volume face - * \param fIdx The index of the current sub-control-volume face - */ - void computeStresses(PrimaryVariables &stress, - const FluxVariables &fluxVars, const int fIdx) const - { - DimMatrix pressure(0.0), sigma(0.0); - // the normal vector corresponding to the current sub-control-volume face - const DimVector &normal(this->fvGeometry_().subContVolFace[fIdx].normal); - - // the pressure term of the momentum balance - for (int i = 0; i < dim; ++i) - pressure[i][i] += 1.0; - - pressure *= fluxVars.pressure(); - // effective stresses - sigma = fluxVars.sigma(); - // calculate total stresses by subtracting the pressure - sigma -= pressure; - - DimVector tmp(0.0); - // multiply total stress tensor with normal vector of current face - sigma.mv(normal, tmp); - - // set the stress term equal to the calculated vector - for (int i = 0; i < dim; ++i) - stress[Indices::momentum(i)] = tmp[i]; - } - - /*! - * \brief Calculate the source term of the equation - * \param source The source/sink in the SCV for each component - * \param scvIdx The index of the vertex of the sub control volume - * - */ - void computeSource(PrimaryVariables &source, const int scvIdx) - { - source = 0; - - const ElementVolumeVariables &elemVolVars = this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[scvIdx]; - - DimVector tmp1(0.0), tmp2(0.0); - - this->problem_().solDependentSource(source, - this->element_(), - this->fvGeometry_(), - scvIdx, - this->curVolVars_()); - - // the gravity term of the momentum balance equation is treated as a source term - // gravity contribution of solid matrix - tmp1 = this->problem_().gravity(); - tmp1 *= volVars.rockDensity(); - tmp1 *= (1. - volVars.effPorosity); - - // gravity contribution of the fluids - tmp2 = this->problem_().gravity(); - tmp2 *= volVars.density(); - tmp2 *= volVars.effPorosity; - - tmp1 += tmp2; - - for (int i = 0; i < dim; ++i) - source[Indices::momentum(i)] += tmp1[i]; - } - - Implementation *asImp_() - { return static_cast<Implementation *> (this); } - const Implementation *asImp_() const - { return static_cast<const Implementation *> (this); } - - private: - Scalar upwindWeight_; - bool withStabilization_; - }; - -} +#include <dumux/geomechanics/el1p2c/localresidual.hh> #endif diff --git a/dumux/geomechanics/el1p2c/el1p2cmodel.hh b/dumux/geomechanics/el1p2c/el1p2cmodel.hh index 7af571e864ae11678c9e5373065249be2869fbae..3294ac54ca2bf72fd5dcf6e5fc7f7b8a75e97cc0 100644 --- a/dumux/geomechanics/el1p2c/el1p2cmodel.hh +++ b/dumux/geomechanics/el1p2c/el1p2cmodel.hh @@ -1,519 +1,8 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * See the file COPYING for full copying permissions. * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -/*! - * \file - * - * \brief Base class for all models which use the one-phase two-component linear elasticity model. - * Adaption of the fully implicit scheme to the one-phase two-component linear elasticity model. - */ -#ifndef DUMUX_ELASTIC1P2C_MODEL_HH -#define DUMUX_ELASTIC1P2C_MODEL_HH +#ifndef DUMUX_ELASTIC1P2C_MODEL_HH_OLD +#define DUMUX_ELASTIC1P2C_MODEL_HH_OLD -#include "el1p2cproperties.hh" -#include <dumux/common/eigenvalues.hh> +#warning this header is deprecated, use dumux/geomechanics/el1p2c/model.hh instead -namespace Dumux { -/*! - * \ingroup ElOnePTwoCBoxModel - * \brief Adaption of the fully implicit scheme to the one-phase two-component linear elasticity model. - * - * This model implements a one-phase flow of an incompressible fluid, that consists of two components. - * The deformation of the solid matrix is described with a quasi-stationary momentum balance equation. - * The influence of the pore fluid is accounted for through the effective stress concept (Biot 1941). - * The total stress acting on a rock is partially supported by the rock matrix and partially supported - * by the pore fluid. The effective stress represents the share of the total stress which is supported - * by the solid rock matrix and can be determined as a function of the strain according to Hooke's law. - * - * As an equation for the conservation of momentum within the fluid phase Darcy's approach is used: - \f[ - v = - \frac{\textbf K}{\mu} - \left(\textbf{grad}\, p - \varrho_w {\textbf g} \right) - \f] - * - * Gravity can be enabled or disabled via the property system. - * By inserting this into the volume balance of the solid-fluid mixture, one gets - \f[ - \frac{\partial \text{div} \textbf{u}}{\partial t} - \text{div} \left\{ - \frac{\textbf K}{\mu} \left(\textbf{grad}\, p - \varrho_w {\textbf g} \right)\right\} = q \;, - \f] - * - * The transport of the components \f$\kappa \in \{ w, a \}\f$ is described by the following equation: - \f[ - \frac{ \partial \phi_{eff} X^\kappa}{\partial t} - - \text{div} \left\lbrace - X^\kappa \frac{{\textbf K}}{\mu} \left( \textbf{grad}\, p - \varrho_w {\textbf g} \right) - + D^\kappa_\text{pm} \frac{M^\kappa}{M_\alpha} \textbf{grad} x^\kappa - - \phi_{eff} X^\kappa \frac{\partial \boldsymbol{u}}{\partial t} - \right\rbrace = q. - \f] - * - * If the model encounters stability problems, a stabilization term can be switched on. The stabilization - * term is defined in Aguilar et al (2008): - \f[ - \beta \text{div} \textbf{grad} \frac{\partial p}{\partial t} - \f] - with \f$\beta\f$: - \f[ - \beta = h^2 / 4(\lambda + 2 \mu) - \f] - * where \f$h\f$ is the discretization length. - * - * The balance equations - * with the stabilization term are given below: - \f[ - \frac{\partial \text{div} \textbf{u}}{\partial t} - \text{div} \left\{ - \frac{\textbf K}{\mu} \left(\textbf{grad}\, p - \varrho_w {\textbf g} \right) - + \varrho_w \beta \textbf{grad} \frac{\partial p}{\partial t} - \right\} = q \;, - \f] - * - * The transport of the components \f$\kappa \in \{ w, a \}\f$ is described by the following equation: - * - \f[ - \frac{ \partial \phi_{eff} X^\kappa}{\partial t} - - \text{div} \left\lbrace - X^\kappa \frac{{\textbf K}}{\mu} \left( \textbf{grad}\, p - \varrho_w {\textbf g} \right) - + \varrho_w X^\kappa \beta \textbf{grad} \frac{\partial p}{\partial t} - + D^\kappa_\text{pm} \frac{M^\kappa}{M_\alpha} \textbf{grad} x^\kappa - - \phi_{eff} X^\kappa \frac{\partial \boldsymbol{u}}{\partial t} - \right\rbrace = q. - \f] - * - * - * The quasi-stationary momentum balance equation is: - \f[ - \text{div}\left( \boldsymbol{\sigma'}- p \boldsymbol{I} \right) + \left( \phi_{eff} \varrho_w + (1 - \phi_{eff}) * \varrho_s \right) - {\textbf g} = 0 \;, - \f] - * with the effective stress: - \f[ - \boldsymbol{\sigma'} = 2\,G\,\boldsymbol{\epsilon} + \lambda \,\text{tr} (\boldsymbol{\epsilon}) \, \boldsymbol{I}. - \f] - * - * and the strain tensor \f$\boldsymbol{\epsilon}\f$ as a function of the solid displacement gradient \f$\textbf{grad} \boldsymbol{u}\f$: - \f[ - \boldsymbol{\epsilon} = \frac{1}{2} \, (\textbf{grad} \boldsymbol{u} + \textbf{grad}^T \boldsymbol{u}). - \f] - * - * Here, the rock mechanics sign convention is switch off which means compressive stresses are < 0 and tensile stresses are > 0. - * The rock mechanics sign convention can be switched on for the vtk output via the property system. - * - * The effective porosity is calculated as a function of the solid displacement: - \f[ - \phi_{eff} = \frac{\phi_{init} + \text{div} \boldsymbol{u}}{1 + \text{div}} - \f] - * All equations are discretized using a vertex-centered finite volume (box) - * or cell-centered finite volume scheme as spatial - * and the implicit Euler method as time discretization. - * - * The primary variables are the pressure \f$p\f$ and the mole or mass fraction of dissolved component \f$x\f$ and the solid - * displacement vector \f$\boldsymbol{u}\f$. - */ +#include <dumux/geomechanics/el1p2c/model.hh> - -template<class TypeTag> -class ElOnePTwoCModel: public GET_PROP_TYPE(TypeTag, BaseModel) -{ - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - enum { - dim = GridView::dimension - }; - - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - -public: - /*! - * \brief \copybrief ImplicitModel::addOutputVtkFields - * - * Specialization for the ElOnePTwoCBoxModel, add one-phase two-component - * properties, solid displacement, stresses, effective properties and the - * process rank to the VTK writer. - */ - template<class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, MultiWriter &writer) { - - // check whether compressive stresses are defined to be positive - // (rockMechanicsSignConvention_ == true) or negative - rockMechanicsSignConvention_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Vtk, RockMechanicsSignConvention); - - typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; - typedef Dune::BlockVector<Dune::FieldVector<Scalar, dim> > VectorField; - - // create the required scalar and vector fields - unsigned numVertices = this->gridView_().size(dim); - unsigned numElements = this->gridView_().size(0); - - // create the required fields for vertex data - ScalarField &pressure = *writer.allocateManagedBuffer(numVertices); - ScalarField &moleFraction0 = *writer.allocateManagedBuffer(numVertices); - ScalarField &moleFraction1 = *writer.allocateManagedBuffer(numVertices); - ScalarField &massFraction0 = *writer.allocateManagedBuffer(numVertices); - ScalarField &massFraction1 = *writer.allocateManagedBuffer(numVertices); - VectorField &displacement = *writer.template allocateManagedBuffer<Scalar, dim>(numVertices); - ScalarField &density = *writer.allocateManagedBuffer(numVertices); - ScalarField &viscosity = *writer.allocateManagedBuffer(numVertices); - ScalarField &porosity = *writer.allocateManagedBuffer(numVertices); - ScalarField &Kx = *writer.allocateManagedBuffer(numVertices); - - // create the required fields for element data - // effective stresses - VectorField &effStressX = *writer.template allocateManagedBuffer<Scalar, - dim>(numElements); - VectorField &effStressY = *writer.template allocateManagedBuffer<Scalar, - dim>(numElements); - VectorField &effStressZ = *writer.template allocateManagedBuffer<Scalar, - dim>(numElements); - // total stresses - VectorField &totalStressX = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - VectorField &totalStressY = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - VectorField &totalStressZ = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - - // principal stresses - ScalarField &principalStress1 = *writer.allocateManagedBuffer( - numElements); - ScalarField &principalStress2 = *writer.allocateManagedBuffer( - numElements); - ScalarField &principalStress3 = *writer.allocateManagedBuffer( - numElements); - - ScalarField &effPorosity = *writer.allocateManagedBuffer(numElements); - ScalarField &cellPorosity = *writer.allocateManagedBuffer(numElements); - ScalarField &cellKx = *writer.allocateManagedBuffer(numElements); - ScalarField &cellPressure = *writer.allocateManagedBuffer(numElements); - - // initialize cell stresses, cell-wise hydraulic parameters and cell pressure with zero - for (unsigned int eIdx = 0; eIdx < numElements; ++eIdx) { - effStressX[eIdx] = Scalar(0.0); - if (dim >= 2) - effStressY[eIdx] = Scalar(0.0); - if (dim >= 3) - effStressZ[eIdx] = Scalar(0.0); - - totalStressX[eIdx] = Scalar(0.0); - if (dim >= 2) - totalStressY[eIdx] = Scalar(0.0); - if (dim >= 3) - totalStressZ[eIdx] = Scalar(0.0); - - principalStress1[eIdx] = Scalar(0.0); - if (dim >= 2) - principalStress2[eIdx] = Scalar(0.0); - if (dim >= 3) - principalStress3[eIdx] = Scalar(0.0); - - effPorosity[eIdx] = Scalar(0.0); - cellPorosity[eIdx] = Scalar(0.0); - cellKx[eIdx] = Scalar(0.0); - cellPressure[eIdx] = Scalar(0.0); - } - ScalarField &rank = *writer.allocateManagedBuffer(numElements); - - - FVElementGeometry fvGeometry; - ElementVolumeVariables elemVolVars; - ElementBoundaryTypes elemBcTypes; - - // initialize start and end of element iterator - // loop over all elements (cells) - for (const auto& element : Dune::elements(this->gridView_())) - { - if(element.partitionType() == Dune::InteriorEntity) - { - unsigned int eIdx = this->problem_().model().elementMapper().index(element); - rank[eIdx] = this->gridView_().comm().rank(); - - fvGeometry.update(this->gridView_(), element); - elemBcTypes.update(this->problem_(), element, fvGeometry); - elemVolVars.update(this->problem_(), element, fvGeometry, false); - - // loop over all local vertices of the cell - int numScv = element.subEntities(dim); - - for (int scvIdx = 0; scvIdx < numScv; ++scvIdx) - { - unsigned int vIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); - - pressure[vIdxGlobal] = elemVolVars[scvIdx].pressure(); - moleFraction0[vIdxGlobal] = elemVolVars[scvIdx].moleFraction(0); - moleFraction1[vIdxGlobal] = elemVolVars[scvIdx].moleFraction(1); - massFraction0[vIdxGlobal] = elemVolVars[scvIdx].massFraction(0); - massFraction1[vIdxGlobal] = elemVolVars[scvIdx].massFraction(1); - // in case of rock mechanics sign convention solid displacement is - // defined to be negative if it points in positive coordinate direction - if(rockMechanicsSignConvention_){ - DimVector tmpDispl; - tmpDispl = Scalar(0); - tmpDispl -= elemVolVars[scvIdx].displacement(); - displacement[vIdxGlobal] = tmpDispl; - } - - else - displacement[vIdxGlobal] = elemVolVars[scvIdx].displacement(); - - density[vIdxGlobal] = elemVolVars[scvIdx].density(); - viscosity[vIdxGlobal] = elemVolVars[scvIdx].viscosity(); - porosity[vIdxGlobal] = elemVolVars[scvIdx].porosity(); - Kx[vIdxGlobal] = this->problem_().spatialParams().intrinsicPermeability( - element, fvGeometry, scvIdx)[0][0]; - // calculate cell quantities by adding up scv quantities and dividing through numScv - cellPorosity[eIdx] += elemVolVars[scvIdx].porosity() / numScv; - cellKx[eIdx] += this->problem_().spatialParams().intrinsicPermeability( - element, fvGeometry, scvIdx)[0][0] / numScv; - cellPressure[eIdx] += elemVolVars[scvIdx].pressure() / numScv; - }; - - // calculate cell quantities for variables which are defined at the integration point - Scalar tmpEffPoro; - DimMatrix tmpEffStress; - tmpEffStress = Scalar(0); - tmpEffPoro = Scalar(0); - - // loop over all scv-faces of the cell - for (int fIdx = 0; fIdx < fvGeometry.numScvf; fIdx++) { - - //prepare the flux calculations (set up and prepare geometry, FE gradients) - FluxVariables fluxVars(this->problem_(), - element, fvGeometry, - fIdx, - elemVolVars); - - // divide by number of scv-faces and sum up edge values - tmpEffPoro = fluxVars.effPorosity() / fvGeometry.numScvf; - tmpEffStress = fluxVars.sigma(); - tmpEffStress /= fvGeometry.numScvf; - - effPorosity[eIdx] += tmpEffPoro; - - // in case of rock mechanics sign convention compressive stresses - // are defined to be positive - if(rockMechanicsSignConvention_){ - effStressX[eIdx] -= tmpEffStress[0]; - if (dim >= 2) { - effStressY[eIdx] -= tmpEffStress[1]; - } - if (dim >= 3) { - effStressZ[eIdx] -= tmpEffStress[2]; - } - } - else{ - effStressX[eIdx] += tmpEffStress[0]; - if (dim >= 2) { - effStressY[eIdx] += tmpEffStress[1]; - } - if (dim >= 3) { - effStressZ[eIdx] += tmpEffStress[2]; - } - } - } - - // calculate total stresses - // in case of rock mechanics sign convention compressive stresses - // are defined to be positive and total stress is calculated by adding the pore pressure - if(rockMechanicsSignConvention_){ - totalStressX[eIdx][0] = effStressX[eIdx][0] + cellPressure[eIdx]; - totalStressX[eIdx][1] = effStressX[eIdx][1]; - totalStressX[eIdx][2] = effStressX[eIdx][2]; - if (dim >= 2) { - totalStressY[eIdx][0] = effStressY[eIdx][0]; - totalStressY[eIdx][1] = effStressY[eIdx][1] + cellPressure[eIdx]; - totalStressY[eIdx][2] = effStressY[eIdx][2]; - } - if (dim >= 3) { - totalStressZ[eIdx][0] = effStressZ[eIdx][0]; - totalStressZ[eIdx][1] = effStressZ[eIdx][1]; - totalStressZ[eIdx][2] = effStressZ[eIdx][2] + cellPressure[eIdx]; - } - } - else{ - totalStressX[eIdx][0] = effStressX[eIdx][0] - cellPressure[eIdx]; - totalStressX[eIdx][1] = effStressX[eIdx][1]; - totalStressX[eIdx][2] = effStressX[eIdx][2]; - if (dim >= 2) { - totalStressY[eIdx][0] = effStressY[eIdx][0]; - totalStressY[eIdx][1] = effStressY[eIdx][1] - cellPressure[eIdx]; - totalStressY[eIdx][2] = effStressY[eIdx][2]; - } - if (dim >= 3) { - totalStressZ[eIdx][0] = effStressZ[eIdx][0]; - totalStressZ[eIdx][1] = effStressZ[eIdx][1]; - totalStressZ[eIdx][2] = effStressZ[eIdx][2] - cellPressure[eIdx]; - } - } - } - } - - // calculate principal stresses i.e. the eigenvalues of the total stress tensor - Scalar a1, a2, a3; - DimMatrix totalStress; - DimVector eigenValues; - a1=Scalar(0); - a2=Scalar(0); - a3=Scalar(0); - - for (unsigned int eIdx = 0; eIdx < numElements; eIdx++) - { - eigenValues = Scalar(0); - totalStress = Scalar(0); - - totalStress[0] = totalStressX[eIdx]; - if (dim >= 2) - totalStress[1] = totalStressY[eIdx]; - if (dim >= 3) - totalStress[2] = totalStressZ[eIdx]; - - calculateEigenValues<dim>(eigenValues, totalStress); - - - for (int i = 0; i < dim; i++) - { - if (isnan(eigenValues[i])) - eigenValues[i] = 0.0; - } - - // sort principal stresses: principalStress1 >= principalStress2 >= principalStress3 - if (dim == 2) { - a1 = eigenValues[0]; - a2 = eigenValues[1]; - - if (a1 >= a2) { - principalStress1[eIdx] = a1; - principalStress2[eIdx] = a2; - } else { - principalStress1[eIdx] = a2; - principalStress2[eIdx] = a1; - } - } - - if (dim == 3) { - a1 = eigenValues[0]; - a2 = eigenValues[1]; - a3 = eigenValues[2]; - - if (a1 >= a2) { - if (a1 >= a3) { - principalStress1[eIdx] = a1; - if (a2 >= a3) { - principalStress2[eIdx] = a2; - principalStress3[eIdx] = a3; - } - else //a3 > a2 - { - principalStress2[eIdx] = a3; - principalStress3[eIdx] = a2; - } - } - else // a3 > a1 - { - principalStress1[eIdx] = a3; - principalStress2[eIdx] = a1; - principalStress3[eIdx] = a2; - } - } else // a2>a1 - { - if (a2 >= a3) { - principalStress1[eIdx] = a2; - if (a1 >= a3) { - principalStress2[eIdx] = a1; - principalStress3[eIdx] = a3; - } - else //a3>a1 - { - principalStress2[eIdx] = a3; - principalStress3[eIdx] = a1; - } - } - else //a3>a2 - { - principalStress1[eIdx] = a3; - principalStress2[eIdx] = a2; - principalStress3[eIdx] = a1; - } - } - } - - } - - writer.attachVertexData(pressure, "P"); - - char nameMoleFraction0[42], nameMoleFraction1[42]; - snprintf(nameMoleFraction0, 42, "x_%s", FluidSystem::componentName(0)); - snprintf(nameMoleFraction1, 42, "x_%s", FluidSystem::componentName(1)); - writer.attachVertexData(moleFraction0, nameMoleFraction0); - writer.attachVertexData(moleFraction1, nameMoleFraction1); - - char nameMassFraction0[42], nameMassFraction1[42]; - snprintf(nameMassFraction0, 42, "X_%s", FluidSystem::componentName(0)); - snprintf(nameMassFraction1, 42, "X_%s", FluidSystem::componentName(1)); - writer.attachVertexData(massFraction0, nameMassFraction0); - writer.attachVertexData(massFraction1, nameMassFraction1); - - writer.attachVertexData(displacement, "u", dim); - writer.attachVertexData(density, "rho"); - writer.attachVertexData(viscosity, "mu"); - writer.attachVertexData(porosity, "porosity"); - writer.attachVertexData(Kx, "Kx"); - writer.attachCellData(cellPorosity, "porosity"); - writer.attachCellData(cellKx, "Kx"); - writer.attachCellData(effPorosity, "effective porosity"); - - writer.attachCellData(totalStressX, "total stresses X", dim); - if (dim >= 2) - writer.attachCellData(totalStressY, "total stresses Y", dim); - if (dim >= 3) - writer.attachCellData(totalStressZ, "total stresses Z", dim); - - writer.attachCellData(effStressX, "effective stress changes X", dim); - if (dim >= 2) - writer.attachCellData(effStressY, "effective stress changes Y", dim); - if (dim >= 3) - writer.attachCellData(effStressZ, "effective stress changes Z", dim); - - writer.attachCellData(principalStress1, "principal stress 1"); - if (dim >= 2) - writer.attachCellData(principalStress2, "principal stress 2"); - if (dim >= 3) - writer.attachCellData(principalStress3, "principal stress 3"); - - writer.attachCellData(cellPressure, "P"); - - writer.attachCellData(rank, "rank"); - - } -private: - bool rockMechanicsSignConvention_; - -}; -} -#include "el1p2cpropertydefaults.hh" #endif diff --git a/dumux/geomechanics/el1p2c/el1p2cproperties.hh b/dumux/geomechanics/el1p2c/el1p2cproperties.hh index 735524c2433c3261799b4d42de1f760df74303a4..2d26172b8c58cd2e3124e18dc267fb2cb0350994 100644 --- a/dumux/geomechanics/el1p2c/el1p2cproperties.hh +++ b/dumux/geomechanics/el1p2c/el1p2cproperties.hh @@ -1,63 +1,8 @@ -// -*- 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/>. * - *****************************************************************************/ -/*! - * \ingroup Properties - * \ingroup ImplicitProperties - * \ingroup ElOnePTwoCBoxModel - * \file - * - * \brief Defines the properties required for the one-phase two-component - * linear elasticity model. - * - * This class inherits from the properties of the one-phase two-component model and - * from the properties of the linear elasticity model - */ +#ifndef DUMUX_ELASTIC1P2C_PROPERTIES_HH_OLD +#define DUMUX_ELASTIC1P2C_PROPERTIES_HH_OLD -#ifndef DUMUX_ELASTIC1P2C_PROPERTIES_HH -#define DUMUX_ELASTIC1P2C_PROPERTIES_HH +#warning this header is deprecated, use dumux/geomechanics/el1p2c/properties.hh instead -#include <dumux/porousmediumflow/1p2c/implicit/properties.hh> -#include <dumux/geomechanics/elastic/elasticproperties.hh> - - -namespace Dumux -{ -// \{ -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tag for the single-phase, two-component linear elasticity problems -NEW_TYPE_TAG(BoxElasticOnePTwoC, INHERITS_FROM(BoxModel)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// -//! Returns whether the stabilization terms are included in the balance equations -NEW_PROP_TAG(ImplicitWithStabilization); -//! Returns whether the output should be written according to rock mechanics sign convention (compressive stresses > 0) -NEW_PROP_TAG(VtkRockMechanicsSignConvention); -} -// \} -} +#include <dumux/geomechanics/el1p2c/properties.hh> #endif - diff --git a/dumux/geomechanics/el1p2c/el1p2cpropertydefaults.hh b/dumux/geomechanics/el1p2c/el1p2cpropertydefaults.hh index 94d1b4c46eb1413248ab60b10e644ef3292aa000..1466b574cb7c7f71bc39ba786bb117619487875b 100644 --- a/dumux/geomechanics/el1p2c/el1p2cpropertydefaults.hh +++ b/dumux/geomechanics/el1p2c/el1p2cpropertydefaults.hh @@ -1,129 +1,8 @@ -// -*- 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/>. * - *****************************************************************************/ -/*! - * \ingroup Properties - * \ingroup ImplicitProperties - * \ingroup ElOnePTwoCBoxModel - * \file - * - * \brief Defines the properties required for the one-phase two-component - * linear-elastic model. - * - * This class inherits from the properties of the one-phase two-component model and - * from the properties of the simple linear-elastic model - */ +#ifndef DUMUX_ELASTIC1P2C_PROPERTY_DEFAULTS_HH_OLD +#define DUMUX_ELASTIC1P2C_PROPERTY_DEFAULTS_HH_OLD -#ifndef DUMUX_ELASTIC1P2C_PROPERTY_DEFAULTS_HH -#define DUMUX_ELASTIC1P2C_PROPERTY_DEFAULTS_HH +#warning this header is deprecated, use dumux/geomechanics/el1p2c/propertydefaults.hh instead -#include "el1p2cproperties.hh" - -#include "el1p2cmodel.hh" -#include "el1p2clocalresidual.hh" -#include "el1p2clocaljacobian.hh" -#include "el1p2cfluxvariables.hh" -#include "el1p2celementvolumevariables.hh" -#include "el1p2cvolumevariables.hh" -#include "el1p2cindices.hh" -#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> -#include <dumux/material/fluidstates/compositionalfluidstate.hh> - - -namespace Dumux -{ -// \{ -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Property defaults -////////////////////////////////////////////////////////////////// -//!< set the number of equations to the space dimension of the problem -SET_PROP(BoxElasticOnePTwoC, NumEq) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum{dim = GridView::dimension}; -public: - static const int value = dim + 2; -}; - -SET_INT_PROP(BoxElasticOnePTwoC, NumPhases, 1); //!< The number of phases in the 1p2c model is 1 -SET_INT_PROP(BoxElasticOnePTwoC, NumComponents, 2); //!< The number of components in the 1p2c model is 2 - -//! Use the linear elasticity local residual function for the elasticity model -SET_TYPE_PROP(BoxElasticOnePTwoC, - LocalResidual, - ElOnePTwoCLocalResidual<TypeTag>); - -//! Use the linear elasticity local residual function for the elasticity model -SET_TYPE_PROP(BoxElasticOnePTwoC, - LocalJacobian, - ElOnePTwoCLocalJacobian<TypeTag>); - -//! define the model -SET_TYPE_PROP(BoxElasticOnePTwoC, Model, ElOnePTwoCModel<TypeTag>); - -//! define the ElementVolumeVariables -SET_TYPE_PROP(BoxElasticOnePTwoC, ElementVolumeVariables, Dumux::ElOnePTwoCElementVolumeVariables<TypeTag>); - -//! define the VolumeVariables -SET_TYPE_PROP(BoxElasticOnePTwoC, VolumeVariables, Dumux::ElOnePTwoCVolumeVariables<TypeTag>); - -//! define the FluxVariables -SET_TYPE_PROP(BoxElasticOnePTwoC, FluxVariables, ElOnePTwoCFluxVariables<TypeTag>); - -//! Set the indices used by the linear elasticity model -SET_TYPE_PROP(BoxElasticOnePTwoC, Indices, ElOnePTwoCIndices<TypeTag>); - -//! Set the phaseIndex per default to zero (important for two-phase fluidsystems). -SET_INT_PROP(BoxElasticOnePTwoC, PhaseIdx, 0); - -SET_PROP(BoxElasticOnePTwoC, FluidState){ - private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - public: - typedef Dumux::CompositionalFluidState<Scalar, FluidSystem> type; -}; - -//! set default upwind weights to 1.0, i.e. fully upwind -SET_SCALAR_PROP(BoxElasticOnePTwoC, ImplicitMassUpwindWeight, 1.0); -SET_SCALAR_PROP(BoxElasticOnePTwoC, ImplicitMobilityUpwindWeight, 1.0); - -// enable gravity by default -SET_BOOL_PROP(BoxElasticOnePTwoC, ProblemEnableGravity, true); - -// enable gravity by default -SET_BOOL_PROP(BoxElasticOnePTwoC, ImplicitWithStabilization, true); - -//! The model after Millington (1961) is used for the effective diffusivity -SET_PROP(BoxElasticOnePTwoC, EffectiveDiffusivityModel) -{ private : - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - public: - typedef DiffusivityMillingtonQuirk<Scalar> type; -}; - -// write the stress and displacement output according to rock mechanics sign convention (compressive stresses > 0) -SET_BOOL_PROP(BoxElasticOnePTwoC, VtkRockMechanicsSignConvention, false); -} -} +#include <dumux/geomechanics/el1p2c/propertydefaults.hh> #endif - diff --git a/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh b/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh index b8d601755921ee40f4fd05c45de2a137ab5bf5c2..336535500f92e01509b463046d454b99c99e9eb5 100644 --- a/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh +++ b/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh @@ -1,205 +1,8 @@ -// -*- 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 Quantities required by the single-phase, two-component - * linear elasticity model which are defined on a vertex. - */ -#ifndef DUMUX_ELASTIC1P2C_VOLUME_VARIABLES_HH -#define DUMUX_ELASTIC1P2C_VOLUME_VARIABLES_HH +#ifndef DUMUX_ELASTIC1P2C_VOLUME_VARIABLES_HH_OLD +#define DUMUX_ELASTIC1P2C_VOLUME_VARIABLES_HH_OLD +#warning this header is deprecated, use dumux/geomechanics/el1p2c/volumevariables.hh instead -#include <dumux/porousmediumflow/1p2c/implicit/volumevariables.hh> -#include <dumux/implicit/volumevariables.hh> - -#include "el1p2cproperties.hh" - -namespace Dumux { -/*! - * \ingroup ElOnePTwoCBoxModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are constant within a - * finite volume in the single-phase, two-component, linear elasticity model. - * - * This class inherits from the volumevariables of the one-phase - * two-component model - */ -template<class TypeTag> -class ElOnePTwoCVolumeVariables : public OnePTwoCVolumeVariables<TypeTag>{ - - typedef OnePTwoCVolumeVariables<TypeTag> ParentType; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - - enum { dim = GridView::dimension }; - - enum { phaseIdx = GET_PROP_VALUE(TypeTag, PhaseIdx) }; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar,dim> DimVector; - -public: - /*! - * \copydoc ImplicitVolumeVariables::update - */ - void update(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int scvIdx, - bool isOldSol) - { - - ParentType::update(priVars, problem, element, fvGeometry, scvIdx, isOldSol); - int vIdxGlobal = problem.vertexMapper().subIndex(element, scvIdx, dim); - - primaryVars_ = priVars; - prevPrimaryVars_ = problem.model().prevSol()[vIdxGlobal]; - - ParentType prev1p2cVolVars; - prev1p2cVolVars.update(problem.model().prevSol()[vIdxGlobal], - problem, - element, - fvGeometry, - scvIdx, - true); - - dPressure_ = this->pressure() - prev1p2cVolVars.pressure(); - - for (int i = 0; i < dim; ++i){ - displacement_[i] = primaryVars_[Indices::u(i)]; - prevDisplacement_[i] = prevPrimaryVars_[Indices::u(i)]; - } - - dU_ = displacement_ - prevDisplacement_; - - const Dune::FieldVector<Scalar, 2> &lameParams = - problem.spatialParams().lameParams(element, fvGeometry, scvIdx); - - lambda_ = lameParams[0]; - mu_ = lameParams[1]; - - rockDensity_ = problem.spatialParams().rockDensity(element, scvIdx); - } - - /*! - * \brief Return the vector of primary variables - */ - const PrimaryVariables &primaryVars() const - { return primaryVars_; } - - /*! - * \brief Sets the evaluation point used in the by the local jacobian. - */ - void setEvalPoint(const Implementation *ep) - { } - - /*! - * \brief Return the Lame parameter lambda \f$\mathrm{[Pa]}\f$ within the control volume. - */ - Scalar lambda() const - { return lambda_; } - - /*! - * \brief Return the Lame parameter mu \f$\mathrm{[Pa]}\f$ within the control volume. - */ - Scalar mu() const - { return mu_; } - - /*! - * \brief Returns the rock density \f$\mathrm{[kg / m^3]}\f$ within the control volume . - */ - Scalar rockDensity() const - { return rockDensity_; } - - /*! - * \brief Returns the change in solid displacement \f$\mathrm{[m]}\f$ between - * the last and the current timestep for the space direction dimIdx within the control volume. - */ - Scalar dU(int dimIdx) const - { return dU_[dimIdx]; } - - /*! - * \brief Returns the change in pressure \f$\mathrm{[Pa]}\f$ between the last and the - * current timestep within the control volume. - */ - Scalar dPressure() const - { return dPressure_; } - - /*! - * \brief Returns the solid displacement \f$\mathrm{[m]}\f$ in space - * directions dimIdx within the control volume. - */ - Scalar displacement(int dimIdx) const - { return displacement_[dimIdx]; } - - /*! - * \brief Returns the solid displacement vector \f$\mathrm{[m]}\f$ - * within the control volume. - */ - const DimVector &displacement() const - { return displacement_; } - - - /*! - * \brief the effective porosity and volumetric strain divU is defined as mutable variable here since it - * is updated within the elementVolumeVariables. - */ - mutable Scalar effPorosity; - mutable Scalar divU; - - /*! - * \brief Returns the mass fraction of a given component in the - * given fluid phase within the control volume. - * - * \param compIdx The component index - */ - Scalar massFraction(const int compIdx) const - { return this->fluidState_.massFraction(phaseIdx, compIdx); } - - /*! - * \brief Returns the mole fraction of a given component in the - * given fluid phase within the control volume. - * - * \param compIdx The component index - */ - Scalar moleFraction(const int compIdx) const - { return this->fluidState_.moleFraction(phaseIdx, compIdx); } - -protected: - PrimaryVariables primaryVars_, prevPrimaryVars_; - DimVector displacement_, prevDisplacement_; - DimVector dU_; - Scalar dPressure_; - Scalar lambda_; - Scalar mu_; - Scalar rockDensity_; -}; - -} +#include <dumux/geomechanics/el1p2c/volumevariables.hh> #endif diff --git a/dumux/geomechanics/el1p2c/elementvolumevariables.hh b/dumux/geomechanics/el1p2c/elementvolumevariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..5d231b8adf9821b8834f8393b1e9d98de6b58d98 --- /dev/null +++ b/dumux/geomechanics/el1p2c/elementvolumevariables.hh @@ -0,0 +1,145 @@ +// -*- 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 Volume variables gathered on an element + */ +#ifndef DUMUX_BOX_EL1P2C_ELEMENT_VOLUME_VARIABLES_HH +#define DUMUX_BOX_EL1P2C_ELEMENT_VOLUME_VARIABLES_HH + +#include <dumux/implicit/box/properties.hh> +#include <dumux/implicit/box/elementvolumevariables.hh> + +namespace Dumux +{ + +/*! + * \ingroup ElOnePTwoCBoxModel + * + * \brief This class stores an array of VolumeVariables objects, one + * volume variables object for each of the element's vertices + */ +template<class TypeTag> +class ElOnePTwoCElementVolumeVariables : public BoxElementVolumeVariables<TypeTag> +{ + typedef BoxElementVolumeVariables<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + enum { dim = GridView::dimension }; + + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + +public: + /*! + * \brief The constructor. + */ + ElOnePTwoCElementVolumeVariables() + { } + + /*! + * \brief Construct the volume variables for all vertices of an element. + * + * \param problem The problem which needs to be simulated. + * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated + * \param fvGeometry The finite volume geometry of the element + * \param oldSol Tells whether the model's previous or current solution should be used. + * + * This class is required for the update of the effective porosity values at the + * vertices since it is a function of the divergence of the solid displacement + * at the integration points + */ + void update(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + bool oldSol) + { + ParentType::update(problem, element, fvGeometry, oldSol); + this->updateEffPorosity(problem, element, fvGeometry); + + }; + + /*! + * \brief Update the effective porosities and the volumetric strain divU for all vertices of an element. + * + * \param problem The problem which needs to be simulated. + * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated + * \param fvGeometry The finite volume geometry of the element + * + * This function is required for the update of the effective porosity / divU values at the + * vertices. + * + * During the partial derivative calculation, changes of the solid displacement + * at vertex i can affect effective porosities / divU of all element vertices. + * To correctly update the effective porosities / divU of all element vertices + * an iteration over all scv faces is required. + * The remaining volvars are only updated for the vertex whose primary variable + * is changed for the derivative calculation. + */ + void updateEffPorosity(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry) + { + // we assert that the i-th shape function is + // associated to the i-th vert of the element. + int numScv = element.subEntities(dim); + + // number of faces which contribute to the porosity value in the sub-control volume + std::vector<double> numContributingFaces; + numContributingFaces.resize(numScv); + + for (int scvIdx = 0; scvIdx < numScv; scvIdx++) { + (*this)[scvIdx].effPorosity = 0.0; + (*this)[scvIdx].divU = 0.0; + numContributingFaces[scvIdx] = 0.0; + } + for (int fIdx = 0; fIdx < fvGeometry.numScvf; fIdx++) + { + // evaluate the gradients at the IPs for each subcontrol volume face + FluxVariables fluxVars(problem, + element, + fvGeometry, + fIdx, + *this); + + numContributingFaces[fluxVars.face().i] += 1; + numContributingFaces[fluxVars.face().j] += 1; + + // average value for the effective porosity + (*this)[fluxVars.face().i].effPorosity += fluxVars.effPorosity(); + (*this)[fluxVars.face().j].effPorosity += fluxVars.effPorosity(); + // average value for the volumetric strain + (*this)[fluxVars.face().i].divU += fluxVars.divU(); + (*this)[fluxVars.face().j].divU += fluxVars.divU(); + + } + for (int scvIdx = 0; scvIdx < numScv; scvIdx++) { + (*this)[scvIdx].effPorosity /= numContributingFaces[scvIdx]; + (*this)[scvIdx].divU /= numContributingFaces[scvIdx]; + } + }; + + +}; + +} // namespace Dumux + +#endif diff --git a/dumux/geomechanics/el1p2c/fluxvariables.hh b/dumux/geomechanics/el1p2c/fluxvariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..f71703a258ee1f8b0051a429586941234486b131 --- /dev/null +++ b/dumux/geomechanics/el1p2c/fluxvariables.hh @@ -0,0 +1,321 @@ +// -*- 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 This file contains the calculation of all the fluxes over the surface of the + * finite volume that make up the volume, the mass and the momentum balance + * for the one-phase two-component linear-elastic model. + * + * This means pressure, concentration and solid-displacement gradients, phase densities at + * the integration point, etc. + * + * This class inherits from the one-phase two-component model FluxVariables and from the + * linear elasticity model FluxVariables + */ +#ifndef DUMUX_ELASTIC1P2C_FLUX_VARIABLES_HH +#define DUMUX_ELASTIC1P2C_FLUX_VARIABLES_HH + +#include <dumux/geomechanics/elastic/fluxvariables.hh> +#include <dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh> + +namespace Dumux +{ +/*! + * \ingroup ElOnePTwoCBoxModel + * \ingroup ImplicitFluxVariables + * \brief This template class contains the data which is required to + * calculate the fluxes over the surface of the + * finite volume that make up the volume, the mass and the momentum balance + * for the one-phase two-component linear-elastic model. + * + * This means pressure, concentration and solid-displacement gradients, phase densities at + * the integration point, etc. + * + */ + template<class TypeTag> + class ElOnePTwoCFluxVariables: public ElasticFluxVariablesBase<TypeTag> , + public OnePTwoCFluxVariables<TypeTag> + { + typedef ElasticFluxVariablesBase<TypeTag> ElasticBase; + typedef OnePTwoCFluxVariables<TypeTag> OnePTwoCBase; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel) EffectiveDiffusivityModel; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + enum + { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + + typedef typename GridView::ctype CoordScalar; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldVector<CoordScalar, dim> DimVector; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; + + public: + /* + * \brief The constructor + * + * \param problem The problem + * \param element The finite element + * \param fvGeometry The finite-volume geometry in the fully implicit scheme + * \param fIdx The local index of the SCV (sub-control-volume) face + * \param elemVolVars The volume variables of the current element + * \param onBoundary A boolean variable to specify whether the flux variables + * are calculated for interior SCV faces or boundary faces, default=false + */ + ElOnePTwoCFluxVariables(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : ElasticBase(problem, element, fvGeometry, fIdx, elemVolVars), + OnePTwoCBase(problem, element, fvGeometry, fIdx, elemVolVars), + fvGeometry_(fvGeometry), faceIdx_(fIdx), onBoundary_(onBoundary) + { + dU_ = Scalar(0); + dGradP_ = Scalar(0); + porosity_ = 0; + effPorosity_ = 0; + pressure_ = 0; + timeDerivUNormal_ = 0; + + elOnePTwoCGradients_(problem, element, elemVolVars); + calculateEffectiveValues_(problem, element, elemVolVars); + calculateDiffCoeffPM_(problem, element, elemVolVars); + calculateDDt_(problem, element, elemVolVars); + + } + ; + + public: + /*! + * \brief Return porosity [-] at the integration point. + */ + Scalar porosity() const + { + return porosity_; + } + + /*! + * \brief Return effective porosity [-] at the integration point. + */ + Scalar effPorosity() const + { + return effPorosity_; + } + + /*! + * \brief Return pressure [Pa] at the integration + * point. + */ + Scalar pressure() const + { + return pressure_; + } + + /*! + * \brief Return change of pressure gradient with time [Pa/m] at + * integration point. + */ + Scalar dGradP(int dimIdx) const + { + return dGradP_[dimIdx]; + } + + /*! + * \brief Return gradient of time derivative of pressure [Pa]. + */ + Scalar timeDerivGradPNormal() const + { + return timeDerivGradPNormal_; + } + + /*! + * \brief Return change of u [m] with time at integration point + * point. + */ + Scalar dU(int dimIdx) const + { + return dU_[dimIdx]; + } + + /*! + * \brief Return time derivative of u [m/s] in normal direction at integration point + */ + Scalar timeDerivUNormal() const + { + return timeDerivUNormal_; + } + + /*! + * \brief Return porous medium diffusion coefficient [m^2] + */ + Scalar diffCoeffPM() const + { + return diffCoeffPM_; + } + + const SCVFace &face() const + { + return fvGeometry_.subContVolFace[faceIdx_]; + } + + protected: + /*! + * \brief Calculation of the solid displacement and pressure gradients. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void elOnePTwoCGradients_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + // calculate gradients + GlobalPosition tmp(0.0); + for (int idx = 0; idx < fvGeometry_.numScv; idx++) // loop over adjacent vertices + { + // FE gradient at vertex idx + const DimVector &feGrad = face().grad[idx]; + + // the gradient of the temporal pressure change (needed for stabilization term) + tmp = feGrad; + tmp *= elemVolVars[idx].dPressure(); + dGradP_ += tmp; + + // average the pressure at integration point + pressure_ += elemVolVars[idx].pressure() + * face().shapeValue[idx]; + // average temporal displacement change at integration point (for calculation of solid displacement velocity) + for (int i = 0; i < dim; ++i) + dU_[i] += elemVolVars[idx].dU(i) + * face().shapeValue[idx]; + // average porosity at integration point + porosity_ += elemVolVars[idx].porosity() + * face().shapeValue[idx]; + } + } + + /*! + * \brief Calculation of the effective porosity. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateEffectiveValues_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + + // the effective porosity is calculated as a function of solid displacement and initial porosity + // according to Han & Dusseault (2003) + + // calculate effective porosity as a function of solid displacement and initial porosity + effPorosity_ = (porosity_ + this->divU()) + / (1 + this->divU()); + } + + /*! + * \brief Calculation of the effective porous media diffusion coefficient. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateDiffCoeffPM_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + const VolumeVariables &volVarsI = elemVolVars[face().i]; + const VolumeVariables &volVarsJ = elemVolVars[face().j]; + + const Scalar diffCoeffI = + EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), + /*sat=*/1.0, + volVarsI.diffCoeff()); + + const Scalar diffCoeffJ = + EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), + /*sat=*/1.0, + volVarsJ.diffCoeff()); + + diffCoeffPM_ = harmonicMean(diffCoeffI, diffCoeffJ); + } + + /*! + * \brief Calculation of the time derivative of solid displacement and pressure gradient + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateDDt_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + Scalar dt= problem.timeManager().timeStepSize(); + DimVector tmp(0.0); + + //time derivative of solid displacement times normal vector + for (int i = 0; i < dim; ++i) + tmp[i] = dU_[i] / dt; + timeDerivUNormal_ = tmp * face().normal; + //time derivative of pressure gradient times normal vector + for (int i = 0; i < dim; ++i) + tmp[i] = dGradP_[i] / dt; + timeDerivGradPNormal_ = tmp * face().normal; + } + + const FVElementGeometry &fvGeometry_; + int faceIdx_; + const bool onBoundary_; + + //! change of solid displacement with time at integration point + GlobalPosition dU_; + //! change of pressure gradient with time at integration point + GlobalPosition dGradP_; + //! porosity at integration point + Scalar porosity_; + //! effective porosity at integration point + Scalar effPorosity_; + //! pressure at integration point + Scalar pressure_; + //! time derivative of solid displacement times normal vector at integration point + Scalar timeDerivUNormal_; + //! time derivative of pressure gradient times normal vector at integration point + Scalar timeDerivGradPNormal_; + //! Parameters + Scalar diffCoeffPM_; + }; + +} // end namespace + +#endif diff --git a/dumux/geomechanics/el1p2c/indices.hh b/dumux/geomechanics/el1p2c/indices.hh new file mode 100644 index 0000000000000000000000000000000000000000..6b5c446286b96ef07e679c79a0720d6ec39ef04e --- /dev/null +++ b/dumux/geomechanics/el1p2c/indices.hh @@ -0,0 +1,53 @@ +// -*- 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 Defines the primary variable and equation indices used by + * the one-phase two-component linear elasticity model. + */ + +#ifndef DUMUX_ELASTIC1P2C_INDICES_HH +#define DUMUX_ELASTIC1P2C_INDICES_HH + +#include <dumux/geomechanics/elastic/indices.hh> +#include <dumux/porousmediumflow/1p2c/implicit/indices.hh> + +namespace Dumux +{ +// \{ + +/*! + * \ingroup ElOnePTwoCBoxModel + * \ingroup ImplicitIndices + * \brief The indices for the one-phase two-component linear elasticity model. + * + * This class inherits from the OnePTwoCIndices and from the ElasticIndices + */ +template <class TypeTag> +// PVOffset is set to 0 for the OnePTwoCIndices and to 2 for the ElasticIndices since +// the first two primary variables are the primary variables of the one-phase two-component +// model followed by the primary variables of the elastic model +class ElOnePTwoCIndices : public OnePTwoCIndices<TypeTag, 0>, public ElasticIndices<2> +{ +}; + +} // namespace Dumux + +#endif diff --git a/dumux/geomechanics/el1p2c/localjacobian.hh b/dumux/geomechanics/el1p2c/localjacobian.hh new file mode 100644 index 0000000000000000000000000000000000000000..4184d8cd4aa2dc93c0fb74f75241a7952d40e224 --- /dev/null +++ b/dumux/geomechanics/el1p2c/localjacobian.hh @@ -0,0 +1,258 @@ +// -*- 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 Calculates the partial derivatives of the local residual for the Jacobian of the + * one-phase two-component linear elasticity model. + */ +#ifndef DUMUX_EL1P2C_LOCAL_JACOBIAN_HH +#define DUMUX_EL1P2C_LOCAL_JACOBIAN_HH + +#include <dumux/implicit/localjacobian.hh> + +namespace Dumux +{ +/*! + * \ingroup ElOnePTwoCBoxModel + * \brief Calculates the partial derivatives of the local residual for the Jacobian + * + * Except for the evalPartialDerivatives function all functions are taken from the + * base class ImplicitLocalJacobian + */ +template<class TypeTag> +class ElOnePTwoCLocalJacobian : public ImplicitLocalJacobian<TypeTag> +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { + dim = GridView::dimension, + }; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + 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, Scalar) Scalar; + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + + // copying a local jacobian is not a good idea + ElOnePTwoCLocalJacobian(const ElOnePTwoCLocalJacobian &); + +public: + ElOnePTwoCLocalJacobian() + {} + + /*! + * \brief Compute the partial derivatives to a primary variable at + * an degree of freedom. + * + * This method is overwritten here since this model requires a call of the model specific + * elementvolumevariables which updates the effective porosities correctly. + * + * 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 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 col, + const int pvIdx) + { + int dofIdxGlobal; + FVElementGeometry neighborFVGeom; + auto neighbor = this->element_(); + if (isBox) + { + dofIdxGlobal = this->vertexMapper_().subIndex(this->element_(), col, dim); + + } + else + { + neighbor = this->fvElemGeom_.neighbors[col]; + neighborFVGeom.updateInner(neighbor); + dofIdxGlobal = this->problemPtr_->elementMapper().index(neighbor); + + } + + PrimaryVariables priVars(this->model_().curSol()[dofIdxGlobal]); + VolumeVariables origVolVars(this->curVolVars_[col]); + + this->curVolVars_[col].setEvalPoint(&origVolVars); + Scalar eps = this->numericEpsilon(col, pvIdx); + Scalar delta = 0; + + if (this->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 + if (isBox){ + this->curVolVars_[col].update(priVars, + this->problem_(), + this->element_(), + this->fvElemGeom_, + col, + false); + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_); + } + else{ + this->curVolVars_[col].update(priVars, + this->problem_(), + neighbor, + neighborFVGeom, + /*scvIdx=*/0, + false); + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_); + } + + this->localResidual().eval(this->element_(), + this->fvElemGeom_, + this->prevVolVars_, + this->curVolVars_, + this->bcTypes_); + + // store the residual and the storage term + partialDeriv = this->localResidual().residual(); + if (isBox || col == 0) + storageDeriv = this->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 = this->residual_; + storageDeriv = this->storageTerm_[col]; + } + + + if (this->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 + if (isBox){ + this->curVolVars_[col].update(priVars, + this->problem_(), + this->element_(), + this->fvElemGeom_, + col, + false); + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_); + } + else{ + this->curVolVars_[col].update(priVars, + this->problem_(), + neighbor, + neighborFVGeom, + /*scvIdx=*/0, + false); + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_); + } + + this->localResidual().eval(this->element_(), + this->fvElemGeom_, + this->prevVolVars_, + this->curVolVars_, + this->bcTypes_); + partialDeriv -= this->localResidual().residual(); + if (isBox || col == 0) + storageDeriv -= this->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 -= this->residual_; + if (isBox || col == 0) + storageDeriv -= this->storageTerm_[col]; + } + + // 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 + this->curVolVars_[col] = origVolVars; + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_); + +#if HAVE_VALGRIND + for (unsigned i = 0; i < partialDeriv.size(); ++i) + Valgrind::CheckDefined(partialDeriv[i]); +#endif + } +}; +} + +#endif diff --git a/dumux/geomechanics/el1p2c/localresidual.hh b/dumux/geomechanics/el1p2c/localresidual.hh new file mode 100644 index 0000000000000000000000000000000000000000..d66085b25b582e2e9670127818954d57820d3ed0 --- /dev/null +++ b/dumux/geomechanics/el1p2c/localresidual.hh @@ -0,0 +1,387 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * + * \brief Element-wise calculation the local Jacobian for the linear elastic, + * single-phase, two-component model in the fully implicit scheme. + */ +#ifndef DUMUX_ELASTIC1P2C_LOCAL_RESIDUAL_HH +#define DUMUX_ELASTIC1P2C_LOCAL_RESIDUAL_HH + +#include "properties.hh" + +namespace Dumux +{ + /*! + * \ingroup ElOnePTwoCModel + * \ingroup ImplicitLocalResidual + * \brief Calculate the local Jacobian for a one-phase two-component + * flow in a linear-elastic porous medium. + * + * This class is used to fill the gaps in BoxLocalResidual for the + * one-phase two-component linear elasticity model. + */ + template<class TypeTag> + class ElOnePTwoCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) + { + protected: + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + enum { dim = GridView::dimension }; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + typedef Dune::FieldVector<Scalar, dim> DimVector; + + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum { + //phase index + phaseIdx = Indices::phaseIdx, + transportCompIdx = Indices::transportCompIdx + }; + // indices of the equations + enum { + conti0EqIdx = Indices::conti0EqIdx, + transportEqIdx = Indices::transportEqIdx + }; + + //! property that defines whether mole or mass fractions are used + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + + + public: + /*! + * \brief Constructor. Sets the upwind weight. + */ + ElOnePTwoCLocalResidual() + { + // retrieve the upwind weight for the mass conservation equations. Use the value + // specified via the property system as default, and overwrite + // it by the run-time parameter from the Dune::ParameterTree + upwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); + // retrieve the property which defines if the stabilization terms in the mass balance + // equations are switched on. Use the value specified via the property system as default, + // and overwrite it by the run-time parameter from the Dune::ParameterTree + withStabilization_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, WithStabilization); + }; + + /*! + * \brief Evaluate the amount of all conservation quantities + * (e.g. phase mass) within a finite volume. + * + * \param storage The mass of the component within the sub-control volume + * \param scvIdx The index of the considered face of the sub-control volume + * \param usePrevSol Evaluate function with solution of current or previous time step + */ + void computeStorage(PrimaryVariables &storage, int scvIdx, + bool usePrevSol) const + { + // if flag usePrevSol is set, the solution from the previous + // time step is used, otherwise the current solution is + // used. The secondary variables are used accordingly. This + // is required to compute the derivative of the storage term + // using the implicit euler method. + const ElementVolumeVariables &elemVolVars = usePrevSol ? this->prevVolVars_() : this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[scvIdx]; + + storage = 0; + // this model assumes incompressible fluids and solids only the bulk + // density i.e. the ratio of solid phase and pore fluid can vary + // storage term of continuity equation + storage[conti0EqIdx] += volVars.divU; + + if(useMoles) + { + // storage term of the transport equation - mole fractions + storage[transportEqIdx] += volVars.moleFraction(transportCompIdx) + * volVars.effPorosity; + } + else + { + //storage term of the transport equation - mass fractions + storage[transportEqIdx] += volVars.massFraction(transportCompIdx) + * volVars.effPorosity; + } + } + + /*! + * \brief Evaluate the mass flux over a face of a sub-control + * volume. + * + * \param flux The flux over the SCV (sub-control-volume) face for each component + * \param fIdx The index of the considered face of the sub control volume + * \param onBoundary A boolean variable to specify whether the flux variables + * are calculated for interior SCV faces or boundary faces, default=false + */ + void computeFlux(PrimaryVariables &flux, int fIdx, const bool onBoundary=false) const + { + flux = 0; + FluxVariables fluxVars(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_()); + + this->computeAdvectiveFlux(flux, fluxVars); + this->computeDiffusiveFlux(flux, fluxVars); + this->computeStresses(flux, fluxVars, fIdx); + } + + /*! + * \brief Evaluates the advective mass flux of all phases over + * a face of a subcontrol volume. + * + * \param flux The advective flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current SCV + */ + void computeAdvectiveFlux(PrimaryVariables &flux, + const FluxVariables &fluxVars) const + { + //////// + // advective fluxes of all components in all phases + //////// + + // data attached to upstream and the downstream vertices + // of the current phase + const VolumeVariables &up = + this->curVolVars_(fluxVars.upstreamIdx()); + const VolumeVariables &dn = + this->curVolVars_(fluxVars.downstreamIdx()); + + // calculate the stabilization term which helps in case of stability problems + // e.g. observed for small time steps (according to G.Aguilar, F.Gaspar, F.Lisbona + // and C.Rodrigo (2008)) + Scalar stabilizationTerm(0.0); + if(withStabilization_){ + // calculate distance h between nodes i and j + const auto geometry = this->element_().geometry(); + DimVector hVec = geometry.corner(fluxVars.face().j) + - geometry.corner(fluxVars.face().i); + Scalar h = hVec.two_norm(); + stabilizationTerm = (h * h) / + (4 * (fluxVars.lambda() + + 2 * fluxVars.mu())); + + stabilizationTerm *= fluxVars.timeDerivGradPNormal(); + } + + + // flux for mass balance of the solid-fluid mixture + // KmvpNormal is the Darcy velocity multiplied with the normal vector, + // calculated in 1p2cfluxvariables.hh + flux[conti0EqIdx] += + fluxVars.KmvpNormal() * + (( upwindWeight_)/up.viscosity() + + + ((1 - upwindWeight_)/dn.viscosity())); + + + // stabilization term + if(withStabilization_) + flux[conti0EqIdx] -= stabilizationTerm; + + if(useMoles) + { + // mass flux of the dissolved second component - massfraction + // advective flux of the component + flux[transportEqIdx] += + fluxVars.KmvpNormal() * + (( upwindWeight_)* up.moleFraction(transportCompIdx)/up.viscosity() + + + (1 - upwindWeight_)* dn.moleFraction(transportCompIdx)/dn.viscosity()); + + // flux of the dissolved second component due to solid displacement + flux[transportEqIdx] += + fluxVars.timeDerivUNormal() * + (( upwindWeight_)* up.moleFraction(transportCompIdx) + * up.effPorosity + + + (1 - upwindWeight_)*dn.moleFraction(transportCompIdx) + * up.effPorosity); + + // stabilization term + if(withStabilization_) + flux[transportEqIdx] -= + stabilizationTerm * + (( upwindWeight_)* up.moleFraction(transportCompIdx) + + + (1 - upwindWeight_)*dn.moleFraction(transportCompIdx)); + } + else + { + // mass flux of the dissolved second component - massfraction + // advective flux of the component + flux[transportEqIdx] += + fluxVars.KmvpNormal() * + (( upwindWeight_)* up.massFraction(transportCompIdx)/up.viscosity() + + + (1 - upwindWeight_)* dn.massFraction(transportCompIdx)/dn.viscosity()); + + // flux of the dissolved second component due to solid displacement + flux[transportEqIdx] += + fluxVars.timeDerivUNormal() * + (( upwindWeight_)* up.massFraction(transportCompIdx) + * up.effPorosity + + + (1 - upwindWeight_)*dn.massFraction(transportCompIdx) + * up.effPorosity); + + // stabilization term + if(withStabilization_) + flux[transportEqIdx] -= + stabilizationTerm * + (( upwindWeight_)* up.massFraction(transportCompIdx) + + + (1 - upwindWeight_)*dn.massFraction(transportCompIdx)); + } + } + + /*! + * \brief Adds the diffusive mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The diffusive flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current sub-control-volume face + */ + void computeDiffusiveFlux(PrimaryVariables &flux, + const FluxVariables &fluxVars) const + { + Scalar tmp(0); + + // diffusive flux of second component + if(useMoles) + { + // diffusive flux of the second component - mole fraction + tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); + tmp *= fluxVars.diffCoeffPM(); + + // dispersive flux of second component - mole fraction + DimVector normalDisp; + fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); + tmp -= (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); + + flux[transportEqIdx] += tmp; + } + else + { + // diffusive flux of the second component - mass fraction + tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); + tmp *= fluxVars.diffCoeffPM(); + + // dispersive flux of second component - mass fraction + DimVector normalDisp; + fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); + tmp -= (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); + + // convert it to a mass flux and add it + flux[transportEqIdx] += tmp * FluidSystem::molarMass(transportCompIdx); + } + } + + /*! + * \brief Evaluates the total stress induced by effective stresses and fluid + * pressure in the solid fluid mixture. + * \param stress The stress over the sub-control-volume face for each component + * \param fluxVars The variables at the current sub-control-volume face + * \param fIdx The index of the current sub-control-volume face + */ + void computeStresses(PrimaryVariables &stress, + const FluxVariables &fluxVars, const int fIdx) const + { + DimMatrix pressure(0.0), sigma(0.0); + // the normal vector corresponding to the current sub-control-volume face + const DimVector &normal(this->fvGeometry_().subContVolFace[fIdx].normal); + + // the pressure term of the momentum balance + for (int i = 0; i < dim; ++i) + pressure[i][i] += 1.0; + + pressure *= fluxVars.pressure(); + // effective stresses + sigma = fluxVars.sigma(); + // calculate total stresses by subtracting the pressure + sigma -= pressure; + + DimVector tmp(0.0); + // multiply total stress tensor with normal vector of current face + sigma.mv(normal, tmp); + + // set the stress term equal to the calculated vector + for (int i = 0; i < dim; ++i) + stress[Indices::momentum(i)] = tmp[i]; + } + + /*! + * \brief Calculate the source term of the equation + * \param source The source/sink in the SCV for each component + * \param scvIdx The index of the vertex of the sub control volume + * + */ + void computeSource(PrimaryVariables &source, const int scvIdx) + { + source = 0; + + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[scvIdx]; + + DimVector tmp1(0.0), tmp2(0.0); + + this->problem_().solDependentSource(source, + this->element_(), + this->fvGeometry_(), + scvIdx, + this->curVolVars_()); + + // the gravity term of the momentum balance equation is treated as a source term + // gravity contribution of solid matrix + tmp1 = this->problem_().gravity(); + tmp1 *= volVars.rockDensity(); + tmp1 *= (1. - volVars.effPorosity); + + // gravity contribution of the fluids + tmp2 = this->problem_().gravity(); + tmp2 *= volVars.density(); + tmp2 *= volVars.effPorosity; + + tmp1 += tmp2; + + for (int i = 0; i < dim; ++i) + source[Indices::momentum(i)] += tmp1[i]; + } + + Implementation *asImp_() + { return static_cast<Implementation *> (this); } + const Implementation *asImp_() const + { return static_cast<const Implementation *> (this); } + + private: + Scalar upwindWeight_; + bool withStabilization_; + }; + +} + +#endif diff --git a/dumux/geomechanics/el1p2c/model.hh b/dumux/geomechanics/el1p2c/model.hh new file mode 100644 index 0000000000000000000000000000000000000000..1e5864d2a94a93ae307a425a8de47a6b1bac8928 --- /dev/null +++ b/dumux/geomechanics/el1p2c/model.hh @@ -0,0 +1,519 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * + * \brief Base class for all models which use the one-phase two-component linear elasticity model. + * Adaption of the fully implicit scheme to the one-phase two-component linear elasticity model. + */ +#ifndef DUMUX_ELASTIC1P2C_MODEL_HH +#define DUMUX_ELASTIC1P2C_MODEL_HH + +#include "properties.hh" +#include <dumux/common/eigenvalues.hh> + +namespace Dumux { +/*! + * \ingroup ElOnePTwoCBoxModel + * \brief Adaption of the fully implicit scheme to the one-phase two-component linear elasticity model. + * + * This model implements a one-phase flow of an incompressible fluid, that consists of two components. + * The deformation of the solid matrix is described with a quasi-stationary momentum balance equation. + * The influence of the pore fluid is accounted for through the effective stress concept (Biot 1941). + * The total stress acting on a rock is partially supported by the rock matrix and partially supported + * by the pore fluid. The effective stress represents the share of the total stress which is supported + * by the solid rock matrix and can be determined as a function of the strain according to Hooke's law. + * + * As an equation for the conservation of momentum within the fluid phase Darcy's approach is used: + \f[ + v = - \frac{\textbf K}{\mu} + \left(\textbf{grad}\, p - \varrho_w {\textbf g} \right) + \f] + * + * Gravity can be enabled or disabled via the property system. + * By inserting this into the volume balance of the solid-fluid mixture, one gets + \f[ + \frac{\partial \text{div} \textbf{u}}{\partial t} - \text{div} \left\{ + \frac{\textbf K}{\mu} \left(\textbf{grad}\, p - \varrho_w {\textbf g} \right)\right\} = q \;, + \f] + * + * The transport of the components \f$\kappa \in \{ w, a \}\f$ is described by the following equation: + \f[ + \frac{ \partial \phi_{eff} X^\kappa}{\partial t} + - \text{div} \left\lbrace + X^\kappa \frac{{\textbf K}}{\mu} \left( \textbf{grad}\, p - \varrho_w {\textbf g} \right) + + D^\kappa_\text{pm} \frac{M^\kappa}{M_\alpha} \textbf{grad} x^\kappa + - \phi_{eff} X^\kappa \frac{\partial \boldsymbol{u}}{\partial t} + \right\rbrace = q. + \f] + * + * If the model encounters stability problems, a stabilization term can be switched on. The stabilization + * term is defined in Aguilar et al (2008): + \f[ + \beta \text{div} \textbf{grad} \frac{\partial p}{\partial t} + \f] + with \f$\beta\f$: + \f[ + \beta = h^2 / 4(\lambda + 2 \mu) + \f] + * where \f$h\f$ is the discretization length. + * + * The balance equations + * with the stabilization term are given below: + \f[ + \frac{\partial \text{div} \textbf{u}}{\partial t} - \text{div} \left\{ + \frac{\textbf K}{\mu} \left(\textbf{grad}\, p - \varrho_w {\textbf g} \right) + + \varrho_w \beta \textbf{grad} \frac{\partial p}{\partial t} + \right\} = q \;, + \f] + * + * The transport of the components \f$\kappa \in \{ w, a \}\f$ is described by the following equation: + * + \f[ + \frac{ \partial \phi_{eff} X^\kappa}{\partial t} + - \text{div} \left\lbrace + X^\kappa \frac{{\textbf K}}{\mu} \left( \textbf{grad}\, p - \varrho_w {\textbf g} \right) + + \varrho_w X^\kappa \beta \textbf{grad} \frac{\partial p}{\partial t} + + D^\kappa_\text{pm} \frac{M^\kappa}{M_\alpha} \textbf{grad} x^\kappa + - \phi_{eff} X^\kappa \frac{\partial \boldsymbol{u}}{\partial t} + \right\rbrace = q. + \f] + * + * + * The quasi-stationary momentum balance equation is: + \f[ + \text{div}\left( \boldsymbol{\sigma'}- p \boldsymbol{I} \right) + \left( \phi_{eff} \varrho_w + (1 - \phi_{eff}) * \varrho_s \right) + {\textbf g} = 0 \;, + \f] + * with the effective stress: + \f[ + \boldsymbol{\sigma'} = 2\,G\,\boldsymbol{\epsilon} + \lambda \,\text{tr} (\boldsymbol{\epsilon}) \, \boldsymbol{I}. + \f] + * + * and the strain tensor \f$\boldsymbol{\epsilon}\f$ as a function of the solid displacement gradient \f$\textbf{grad} \boldsymbol{u}\f$: + \f[ + \boldsymbol{\epsilon} = \frac{1}{2} \, (\textbf{grad} \boldsymbol{u} + \textbf{grad}^T \boldsymbol{u}). + \f] + * + * Here, the rock mechanics sign convention is switch off which means compressive stresses are < 0 and tensile stresses are > 0. + * The rock mechanics sign convention can be switched on for the vtk output via the property system. + * + * The effective porosity is calculated as a function of the solid displacement: + \f[ + \phi_{eff} = \frac{\phi_{init} + \text{div} \boldsymbol{u}}{1 + \text{div}} + \f] + * All equations are discretized using a vertex-centered finite volume (box) + * or cell-centered finite volume scheme as spatial + * and the implicit Euler method as time discretization. + * + * The primary variables are the pressure \f$p\f$ and the mole or mass fraction of dissolved component \f$x\f$ and the solid + * displacement vector \f$\boldsymbol{u}\f$. + */ + + +template<class TypeTag> +class ElOnePTwoCModel: public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + enum { + dim = GridView::dimension + }; + + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + +public: + /*! + * \brief \copybrief ImplicitModel::addOutputVtkFields + * + * Specialization for the ElOnePTwoCBoxModel, add one-phase two-component + * properties, solid displacement, stresses, effective properties and the + * process rank to the VTK writer. + */ + template<class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, MultiWriter &writer) { + + // check whether compressive stresses are defined to be positive + // (rockMechanicsSignConvention_ == true) or negative + rockMechanicsSignConvention_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Vtk, RockMechanicsSignConvention); + + typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<Scalar, dim> > VectorField; + + // create the required scalar and vector fields + unsigned numVertices = this->gridView_().size(dim); + unsigned numElements = this->gridView_().size(0); + + // create the required fields for vertex data + ScalarField &pressure = *writer.allocateManagedBuffer(numVertices); + ScalarField &moleFraction0 = *writer.allocateManagedBuffer(numVertices); + ScalarField &moleFraction1 = *writer.allocateManagedBuffer(numVertices); + ScalarField &massFraction0 = *writer.allocateManagedBuffer(numVertices); + ScalarField &massFraction1 = *writer.allocateManagedBuffer(numVertices); + VectorField &displacement = *writer.template allocateManagedBuffer<Scalar, dim>(numVertices); + ScalarField &density = *writer.allocateManagedBuffer(numVertices); + ScalarField &viscosity = *writer.allocateManagedBuffer(numVertices); + ScalarField &porosity = *writer.allocateManagedBuffer(numVertices); + ScalarField &Kx = *writer.allocateManagedBuffer(numVertices); + + // create the required fields for element data + // effective stresses + VectorField &effStressX = *writer.template allocateManagedBuffer<Scalar, + dim>(numElements); + VectorField &effStressY = *writer.template allocateManagedBuffer<Scalar, + dim>(numElements); + VectorField &effStressZ = *writer.template allocateManagedBuffer<Scalar, + dim>(numElements); + // total stresses + VectorField &totalStressX = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + VectorField &totalStressY = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + VectorField &totalStressZ = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + + // principal stresses + ScalarField &principalStress1 = *writer.allocateManagedBuffer( + numElements); + ScalarField &principalStress2 = *writer.allocateManagedBuffer( + numElements); + ScalarField &principalStress3 = *writer.allocateManagedBuffer( + numElements); + + ScalarField &effPorosity = *writer.allocateManagedBuffer(numElements); + ScalarField &cellPorosity = *writer.allocateManagedBuffer(numElements); + ScalarField &cellKx = *writer.allocateManagedBuffer(numElements); + ScalarField &cellPressure = *writer.allocateManagedBuffer(numElements); + + // initialize cell stresses, cell-wise hydraulic parameters and cell pressure with zero + for (unsigned int eIdx = 0; eIdx < numElements; ++eIdx) { + effStressX[eIdx] = Scalar(0.0); + if (dim >= 2) + effStressY[eIdx] = Scalar(0.0); + if (dim >= 3) + effStressZ[eIdx] = Scalar(0.0); + + totalStressX[eIdx] = Scalar(0.0); + if (dim >= 2) + totalStressY[eIdx] = Scalar(0.0); + if (dim >= 3) + totalStressZ[eIdx] = Scalar(0.0); + + principalStress1[eIdx] = Scalar(0.0); + if (dim >= 2) + principalStress2[eIdx] = Scalar(0.0); + if (dim >= 3) + principalStress3[eIdx] = Scalar(0.0); + + effPorosity[eIdx] = Scalar(0.0); + cellPorosity[eIdx] = Scalar(0.0); + cellKx[eIdx] = Scalar(0.0); + cellPressure[eIdx] = Scalar(0.0); + } + ScalarField &rank = *writer.allocateManagedBuffer(numElements); + + + FVElementGeometry fvGeometry; + ElementVolumeVariables elemVolVars; + ElementBoundaryTypes elemBcTypes; + + // initialize start and end of element iterator + // loop over all elements (cells) + for (const auto& element : Dune::elements(this->gridView_())) + { + if(element.partitionType() == Dune::InteriorEntity) + { + unsigned int eIdx = this->problem_().model().elementMapper().index(element); + rank[eIdx] = this->gridView_().comm().rank(); + + fvGeometry.update(this->gridView_(), element); + elemBcTypes.update(this->problem_(), element, fvGeometry); + elemVolVars.update(this->problem_(), element, fvGeometry, false); + + // loop over all local vertices of the cell + int numScv = element.subEntities(dim); + + for (int scvIdx = 0; scvIdx < numScv; ++scvIdx) + { + unsigned int vIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); + + pressure[vIdxGlobal] = elemVolVars[scvIdx].pressure(); + moleFraction0[vIdxGlobal] = elemVolVars[scvIdx].moleFraction(0); + moleFraction1[vIdxGlobal] = elemVolVars[scvIdx].moleFraction(1); + massFraction0[vIdxGlobal] = elemVolVars[scvIdx].massFraction(0); + massFraction1[vIdxGlobal] = elemVolVars[scvIdx].massFraction(1); + // in case of rock mechanics sign convention solid displacement is + // defined to be negative if it points in positive coordinate direction + if(rockMechanicsSignConvention_){ + DimVector tmpDispl; + tmpDispl = Scalar(0); + tmpDispl -= elemVolVars[scvIdx].displacement(); + displacement[vIdxGlobal] = tmpDispl; + } + + else + displacement[vIdxGlobal] = elemVolVars[scvIdx].displacement(); + + density[vIdxGlobal] = elemVolVars[scvIdx].density(); + viscosity[vIdxGlobal] = elemVolVars[scvIdx].viscosity(); + porosity[vIdxGlobal] = elemVolVars[scvIdx].porosity(); + Kx[vIdxGlobal] = this->problem_().spatialParams().intrinsicPermeability( + element, fvGeometry, scvIdx)[0][0]; + // calculate cell quantities by adding up scv quantities and dividing through numScv + cellPorosity[eIdx] += elemVolVars[scvIdx].porosity() / numScv; + cellKx[eIdx] += this->problem_().spatialParams().intrinsicPermeability( + element, fvGeometry, scvIdx)[0][0] / numScv; + cellPressure[eIdx] += elemVolVars[scvIdx].pressure() / numScv; + }; + + // calculate cell quantities for variables which are defined at the integration point + Scalar tmpEffPoro; + DimMatrix tmpEffStress; + tmpEffStress = Scalar(0); + tmpEffPoro = Scalar(0); + + // loop over all scv-faces of the cell + for (int fIdx = 0; fIdx < fvGeometry.numScvf; fIdx++) { + + //prepare the flux calculations (set up and prepare geometry, FE gradients) + FluxVariables fluxVars(this->problem_(), + element, fvGeometry, + fIdx, + elemVolVars); + + // divide by number of scv-faces and sum up edge values + tmpEffPoro = fluxVars.effPorosity() / fvGeometry.numScvf; + tmpEffStress = fluxVars.sigma(); + tmpEffStress /= fvGeometry.numScvf; + + effPorosity[eIdx] += tmpEffPoro; + + // in case of rock mechanics sign convention compressive stresses + // are defined to be positive + if(rockMechanicsSignConvention_){ + effStressX[eIdx] -= tmpEffStress[0]; + if (dim >= 2) { + effStressY[eIdx] -= tmpEffStress[1]; + } + if (dim >= 3) { + effStressZ[eIdx] -= tmpEffStress[2]; + } + } + else{ + effStressX[eIdx] += tmpEffStress[0]; + if (dim >= 2) { + effStressY[eIdx] += tmpEffStress[1]; + } + if (dim >= 3) { + effStressZ[eIdx] += tmpEffStress[2]; + } + } + } + + // calculate total stresses + // in case of rock mechanics sign convention compressive stresses + // are defined to be positive and total stress is calculated by adding the pore pressure + if(rockMechanicsSignConvention_){ + totalStressX[eIdx][0] = effStressX[eIdx][0] + cellPressure[eIdx]; + totalStressX[eIdx][1] = effStressX[eIdx][1]; + totalStressX[eIdx][2] = effStressX[eIdx][2]; + if (dim >= 2) { + totalStressY[eIdx][0] = effStressY[eIdx][0]; + totalStressY[eIdx][1] = effStressY[eIdx][1] + cellPressure[eIdx]; + totalStressY[eIdx][2] = effStressY[eIdx][2]; + } + if (dim >= 3) { + totalStressZ[eIdx][0] = effStressZ[eIdx][0]; + totalStressZ[eIdx][1] = effStressZ[eIdx][1]; + totalStressZ[eIdx][2] = effStressZ[eIdx][2] + cellPressure[eIdx]; + } + } + else{ + totalStressX[eIdx][0] = effStressX[eIdx][0] - cellPressure[eIdx]; + totalStressX[eIdx][1] = effStressX[eIdx][1]; + totalStressX[eIdx][2] = effStressX[eIdx][2]; + if (dim >= 2) { + totalStressY[eIdx][0] = effStressY[eIdx][0]; + totalStressY[eIdx][1] = effStressY[eIdx][1] - cellPressure[eIdx]; + totalStressY[eIdx][2] = effStressY[eIdx][2]; + } + if (dim >= 3) { + totalStressZ[eIdx][0] = effStressZ[eIdx][0]; + totalStressZ[eIdx][1] = effStressZ[eIdx][1]; + totalStressZ[eIdx][2] = effStressZ[eIdx][2] - cellPressure[eIdx]; + } + } + } + } + + // calculate principal stresses i.e. the eigenvalues of the total stress tensor + Scalar a1, a2, a3; + DimMatrix totalStress; + DimVector eigenValues; + a1=Scalar(0); + a2=Scalar(0); + a3=Scalar(0); + + for (unsigned int eIdx = 0; eIdx < numElements; eIdx++) + { + eigenValues = Scalar(0); + totalStress = Scalar(0); + + totalStress[0] = totalStressX[eIdx]; + if (dim >= 2) + totalStress[1] = totalStressY[eIdx]; + if (dim >= 3) + totalStress[2] = totalStressZ[eIdx]; + + calculateEigenValues<dim>(eigenValues, totalStress); + + + for (int i = 0; i < dim; i++) + { + if (isnan(eigenValues[i])) + eigenValues[i] = 0.0; + } + + // sort principal stresses: principalStress1 >= principalStress2 >= principalStress3 + if (dim == 2) { + a1 = eigenValues[0]; + a2 = eigenValues[1]; + + if (a1 >= a2) { + principalStress1[eIdx] = a1; + principalStress2[eIdx] = a2; + } else { + principalStress1[eIdx] = a2; + principalStress2[eIdx] = a1; + } + } + + if (dim == 3) { + a1 = eigenValues[0]; + a2 = eigenValues[1]; + a3 = eigenValues[2]; + + if (a1 >= a2) { + if (a1 >= a3) { + principalStress1[eIdx] = a1; + if (a2 >= a3) { + principalStress2[eIdx] = a2; + principalStress3[eIdx] = a3; + } + else //a3 > a2 + { + principalStress2[eIdx] = a3; + principalStress3[eIdx] = a2; + } + } + else // a3 > a1 + { + principalStress1[eIdx] = a3; + principalStress2[eIdx] = a1; + principalStress3[eIdx] = a2; + } + } else // a2>a1 + { + if (a2 >= a3) { + principalStress1[eIdx] = a2; + if (a1 >= a3) { + principalStress2[eIdx] = a1; + principalStress3[eIdx] = a3; + } + else //a3>a1 + { + principalStress2[eIdx] = a3; + principalStress3[eIdx] = a1; + } + } + else //a3>a2 + { + principalStress1[eIdx] = a3; + principalStress2[eIdx] = a2; + principalStress3[eIdx] = a1; + } + } + } + + } + + writer.attachVertexData(pressure, "P"); + + char nameMoleFraction0[42], nameMoleFraction1[42]; + snprintf(nameMoleFraction0, 42, "x_%s", FluidSystem::componentName(0)); + snprintf(nameMoleFraction1, 42, "x_%s", FluidSystem::componentName(1)); + writer.attachVertexData(moleFraction0, nameMoleFraction0); + writer.attachVertexData(moleFraction1, nameMoleFraction1); + + char nameMassFraction0[42], nameMassFraction1[42]; + snprintf(nameMassFraction0, 42, "X_%s", FluidSystem::componentName(0)); + snprintf(nameMassFraction1, 42, "X_%s", FluidSystem::componentName(1)); + writer.attachVertexData(massFraction0, nameMassFraction0); + writer.attachVertexData(massFraction1, nameMassFraction1); + + writer.attachVertexData(displacement, "u", dim); + writer.attachVertexData(density, "rho"); + writer.attachVertexData(viscosity, "mu"); + writer.attachVertexData(porosity, "porosity"); + writer.attachVertexData(Kx, "Kx"); + writer.attachCellData(cellPorosity, "porosity"); + writer.attachCellData(cellKx, "Kx"); + writer.attachCellData(effPorosity, "effective porosity"); + + writer.attachCellData(totalStressX, "total stresses X", dim); + if (dim >= 2) + writer.attachCellData(totalStressY, "total stresses Y", dim); + if (dim >= 3) + writer.attachCellData(totalStressZ, "total stresses Z", dim); + + writer.attachCellData(effStressX, "effective stress changes X", dim); + if (dim >= 2) + writer.attachCellData(effStressY, "effective stress changes Y", dim); + if (dim >= 3) + writer.attachCellData(effStressZ, "effective stress changes Z", dim); + + writer.attachCellData(principalStress1, "principal stress 1"); + if (dim >= 2) + writer.attachCellData(principalStress2, "principal stress 2"); + if (dim >= 3) + writer.attachCellData(principalStress3, "principal stress 3"); + + writer.attachCellData(cellPressure, "P"); + + writer.attachCellData(rank, "rank"); + + } +private: + bool rockMechanicsSignConvention_; + +}; +} +#include "propertydefaults.hh" +#endif diff --git a/dumux/geomechanics/el1p2c/properties.hh b/dumux/geomechanics/el1p2c/properties.hh new file mode 100644 index 0000000000000000000000000000000000000000..66970504124e9932b7cca2a646b6cde3e98de288 --- /dev/null +++ b/dumux/geomechanics/el1p2c/properties.hh @@ -0,0 +1,62 @@ +// -*- 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/>. * + *****************************************************************************/ +/*! + * \ingroup Properties + * \ingroup ImplicitProperties + * \ingroup ElOnePTwoCBoxModel + * \file + * + * \brief Defines the properties required for the one-phase two-component + * linear elasticity model. + * + * This class inherits from the properties of the one-phase two-component model and + * from the properties of the linear elasticity model + */ + +#ifndef DUMUX_ELASTIC1P2C_PROPERTIES_HH +#define DUMUX_ELASTIC1P2C_PROPERTIES_HH + +#include <dumux/porousmediumflow/1p2c/implicit/properties.hh> +#include <dumux/geomechanics/elastic/properties.hh> + + +namespace Dumux +{ +// \{ +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tag for the single-phase, two-component linear elasticity problems +NEW_TYPE_TAG(BoxElasticOnePTwoC, INHERITS_FROM(BoxModel)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// +//! Returns whether the stabilization terms are included in the balance equations +NEW_PROP_TAG(ImplicitWithStabilization); +//! Returns whether the output should be written according to rock mechanics sign convention (compressive stresses > 0) +NEW_PROP_TAG(VtkRockMechanicsSignConvention); +} +// \} +} + +#endif diff --git a/dumux/geomechanics/el1p2c/propertydefaults.hh b/dumux/geomechanics/el1p2c/propertydefaults.hh new file mode 100644 index 0000000000000000000000000000000000000000..594beb5cd6eab3cf5682555d7e08ac0b8480f124 --- /dev/null +++ b/dumux/geomechanics/el1p2c/propertydefaults.hh @@ -0,0 +1,128 @@ +// -*- 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/>. * + *****************************************************************************/ +/*! + * \ingroup Properties + * \ingroup ImplicitProperties + * \ingroup ElOnePTwoCBoxModel + * \file + * + * \brief Defines the properties required for the one-phase two-component + * linear-elastic model. + * + * This class inherits from the properties of the one-phase two-component model and + * from the properties of the simple linear-elastic model + */ + +#ifndef DUMUX_ELASTIC1P2C_PROPERTY_DEFAULTS_HH +#define DUMUX_ELASTIC1P2C_PROPERTY_DEFAULTS_HH + +#include "properties.hh" + +#include "model.hh" +#include "localresidual.hh" +#include "localjacobian.hh" +#include "fluxvariables.hh" +#include "elementvolumevariables.hh" +#include "volumevariables.hh" +#include "indices.hh" +#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> +#include <dumux/material/fluidstates/compositionalfluidstate.hh> + + +namespace Dumux +{ +// \{ +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Property defaults +////////////////////////////////////////////////////////////////// +//!< set the number of equations to the space dimension of the problem +SET_PROP(BoxElasticOnePTwoC, NumEq) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum{dim = GridView::dimension}; +public: + static const int value = dim + 2; +}; + +SET_INT_PROP(BoxElasticOnePTwoC, NumPhases, 1); //!< The number of phases in the 1p2c model is 1 +SET_INT_PROP(BoxElasticOnePTwoC, NumComponents, 2); //!< The number of components in the 1p2c model is 2 + +//! Use the linear elasticity local residual function for the elasticity model +SET_TYPE_PROP(BoxElasticOnePTwoC, + LocalResidual, + ElOnePTwoCLocalResidual<TypeTag>); + +//! Use the linear elasticity local residual function for the elasticity model +SET_TYPE_PROP(BoxElasticOnePTwoC, + LocalJacobian, + ElOnePTwoCLocalJacobian<TypeTag>); + +//! define the model +SET_TYPE_PROP(BoxElasticOnePTwoC, Model, ElOnePTwoCModel<TypeTag>); + +//! define the ElementVolumeVariables +SET_TYPE_PROP(BoxElasticOnePTwoC, ElementVolumeVariables, Dumux::ElOnePTwoCElementVolumeVariables<TypeTag>); + +//! define the VolumeVariables +SET_TYPE_PROP(BoxElasticOnePTwoC, VolumeVariables, Dumux::ElOnePTwoCVolumeVariables<TypeTag>); + +//! define the FluxVariables +SET_TYPE_PROP(BoxElasticOnePTwoC, FluxVariables, ElOnePTwoCFluxVariables<TypeTag>); + +//! Set the indices used by the linear elasticity model +SET_TYPE_PROP(BoxElasticOnePTwoC, Indices, ElOnePTwoCIndices<TypeTag>); + +//! Set the phaseIndex per default to zero (important for two-phase fluidsystems). +SET_INT_PROP(BoxElasticOnePTwoC, PhaseIdx, 0); + +SET_PROP(BoxElasticOnePTwoC, FluidState){ + private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + public: + typedef Dumux::CompositionalFluidState<Scalar, FluidSystem> type; +}; + +//! set default upwind weights to 1.0, i.e. fully upwind +SET_SCALAR_PROP(BoxElasticOnePTwoC, ImplicitMassUpwindWeight, 1.0); +SET_SCALAR_PROP(BoxElasticOnePTwoC, ImplicitMobilityUpwindWeight, 1.0); + +// enable gravity by default +SET_BOOL_PROP(BoxElasticOnePTwoC, ProblemEnableGravity, true); + +// enable gravity by default +SET_BOOL_PROP(BoxElasticOnePTwoC, ImplicitWithStabilization, true); + +//! The model after Millington (1961) is used for the effective diffusivity +SET_PROP(BoxElasticOnePTwoC, EffectiveDiffusivityModel) +{ private : + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + public: + typedef DiffusivityMillingtonQuirk<Scalar> type; +}; + +// write the stress and displacement output according to rock mechanics sign convention (compressive stresses > 0) +SET_BOOL_PROP(BoxElasticOnePTwoC, VtkRockMechanicsSignConvention, false); +} +} + +#endif diff --git a/dumux/geomechanics/el1p2c/volumevariables.hh b/dumux/geomechanics/el1p2c/volumevariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..f3773ece1077e80e287c82abb0b639c712e7a36c --- /dev/null +++ b/dumux/geomechanics/el1p2c/volumevariables.hh @@ -0,0 +1,205 @@ +// -*- 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 Quantities required by the single-phase, two-component + * linear elasticity model which are defined on a vertex. + */ +#ifndef DUMUX_ELASTIC1P2C_VOLUME_VARIABLES_HH +#define DUMUX_ELASTIC1P2C_VOLUME_VARIABLES_HH + + +#include <dumux/porousmediumflow/1p2c/implicit/volumevariables.hh> +#include <dumux/implicit/volumevariables.hh> + +#include "properties.hh" + +namespace Dumux { +/*! + * \ingroup ElOnePTwoCBoxModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are constant within a + * finite volume in the single-phase, two-component, linear elasticity model. + * + * This class inherits from the volumevariables of the one-phase + * two-component model + */ +template<class TypeTag> +class ElOnePTwoCVolumeVariables : public OnePTwoCVolumeVariables<TypeTag>{ + + typedef OnePTwoCVolumeVariables<TypeTag> ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + + enum { dim = GridView::dimension }; + + enum { phaseIdx = GET_PROP_VALUE(TypeTag, PhaseIdx) }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar,dim> DimVector; + +public: + /*! + * \copydoc ImplicitVolumeVariables::update + */ + void update(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx, + bool isOldSol) + { + + ParentType::update(priVars, problem, element, fvGeometry, scvIdx, isOldSol); + int vIdxGlobal = problem.vertexMapper().subIndex(element, scvIdx, dim); + + primaryVars_ = priVars; + prevPrimaryVars_ = problem.model().prevSol()[vIdxGlobal]; + + ParentType prev1p2cVolVars; + prev1p2cVolVars.update(problem.model().prevSol()[vIdxGlobal], + problem, + element, + fvGeometry, + scvIdx, + true); + + dPressure_ = this->pressure() - prev1p2cVolVars.pressure(); + + for (int i = 0; i < dim; ++i){ + displacement_[i] = primaryVars_[Indices::u(i)]; + prevDisplacement_[i] = prevPrimaryVars_[Indices::u(i)]; + } + + dU_ = displacement_ - prevDisplacement_; + + const Dune::FieldVector<Scalar, 2> &lameParams = + problem.spatialParams().lameParams(element, fvGeometry, scvIdx); + + lambda_ = lameParams[0]; + mu_ = lameParams[1]; + + rockDensity_ = problem.spatialParams().rockDensity(element, scvIdx); + } + + /*! + * \brief Return the vector of primary variables + */ + const PrimaryVariables &primaryVars() const + { return primaryVars_; } + + /*! + * \brief Sets the evaluation point used in the by the local jacobian. + */ + void setEvalPoint(const Implementation *ep) + { } + + /*! + * \brief Return the Lame parameter lambda \f$\mathrm{[Pa]}\f$ within the control volume. + */ + Scalar lambda() const + { return lambda_; } + + /*! + * \brief Return the Lame parameter mu \f$\mathrm{[Pa]}\f$ within the control volume. + */ + Scalar mu() const + { return mu_; } + + /*! + * \brief Returns the rock density \f$\mathrm{[kg / m^3]}\f$ within the control volume . + */ + Scalar rockDensity() const + { return rockDensity_; } + + /*! + * \brief Returns the change in solid displacement \f$\mathrm{[m]}\f$ between + * the last and the current timestep for the space direction dimIdx within the control volume. + */ + Scalar dU(int dimIdx) const + { return dU_[dimIdx]; } + + /*! + * \brief Returns the change in pressure \f$\mathrm{[Pa]}\f$ between the last and the + * current timestep within the control volume. + */ + Scalar dPressure() const + { return dPressure_; } + + /*! + * \brief Returns the solid displacement \f$\mathrm{[m]}\f$ in space + * directions dimIdx within the control volume. + */ + Scalar displacement(int dimIdx) const + { return displacement_[dimIdx]; } + + /*! + * \brief Returns the solid displacement vector \f$\mathrm{[m]}\f$ + * within the control volume. + */ + const DimVector &displacement() const + { return displacement_; } + + + /*! + * \brief the effective porosity and volumetric strain divU is defined as mutable variable here since it + * is updated within the elementVolumeVariables. + */ + mutable Scalar effPorosity; + mutable Scalar divU; + + /*! + * \brief Returns the mass fraction of a given component in the + * given fluid phase within the control volume. + * + * \param compIdx The component index + */ + Scalar massFraction(const int compIdx) const + { return this->fluidState_.massFraction(phaseIdx, compIdx); } + + /*! + * \brief Returns the mole fraction of a given component in the + * given fluid phase within the control volume. + * + * \param compIdx The component index + */ + Scalar moleFraction(const int compIdx) const + { return this->fluidState_.moleFraction(phaseIdx, compIdx); } + +protected: + PrimaryVariables primaryVars_, prevPrimaryVars_; + DimVector displacement_, prevDisplacement_; + DimVector dU_; + Scalar dPressure_; + Scalar lambda_; + Scalar mu_; + Scalar rockDensity_; +}; + +} + +#endif diff --git a/dumux/geomechanics/el2p/amgbackend.hh b/dumux/geomechanics/el2p/amgbackend.hh new file mode 100644 index 0000000000000000000000000000000000000000..1a8a04d6c76925f557ae13d4b9986cf6b751448f --- /dev/null +++ b/dumux/geomechanics/el2p/amgbackend.hh @@ -0,0 +1,235 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \ingroup Linear + * + * \brief Wraps the AMG backend such that it can be used for the el2p model. + */ +#ifndef DUMUX_EL2P_AMGBACKEND_HH +#define DUMUX_EL2P_AMGBACKEND_HH + +#include <dumux/linear/amgbackend.hh> + +namespace Dumux { + +/*! + * \brief Base class for the ElTwoP AMGBackend. + */ +template <class TypeTag, bool isParallel> +class El2PAMGBackendBase : public AMGBackend<TypeTag> +{ + typedef AMGBackend<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + +public: + /*! + * \copydoc AMGBackend::AMGBackend() + */ + El2PAMGBackendBase(const Problem& problem) + : ParentType(problem) + {} +}; + +/*! + * \brief Specialization for the parallel setting. + */ +template <class TypeTag> +class El2PAMGBackendBase<TypeTag, true> : public AMGBackend<TypeTag> +{ + typedef AMGBackend<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + typedef typename Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; + typedef typename Dune::BCRSMatrix<MatrixBlock> BlockMatrix; + typedef typename Dune::FieldVector<Scalar, numEq> VectorBlock; + typedef typename Dune::BlockVector<VectorBlock> BlockVector; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { dim = GridView::dimension }; + +public: + /*! + * \copydoc AMGBackend::AMGBackend() + */ + El2PAMGBackendBase(const Problem& problem) + : ParentType(problem) + { + createBlockMatrixAndVectors_(); + } + + /*! + * \copydoc AMGBackend::solve() + */ + template<class Matrix, class Vector> + bool solve(Matrix& A, Vector& x, Vector& b) + { + flatToBlocked_(A, x, b); + int converged = ParentType::solve(*aBlocked_, *xBlocked_, *bBlocked_); + blockedToFlat_(x, b); + return converged; + } + +private: + void createBlockMatrixAndVectors_() + { + int numVertices = this->problem().gridView().size(dim); + + aBlocked_ = std::make_shared<BlockMatrix>(numVertices, numVertices, BlockMatrix::random); + xBlocked_ = std::make_shared<BlockVector>(numVertices); + bBlocked_ = std::make_shared<BlockVector>(numVertices); + + // find out the global indices of the neighboring vertices of + // each vertex + typedef std::set<int> NeighborSet; + std::vector<NeighborSet> neighbors(numVertices); + for (const auto& element : Dune::elements(this->problem().gridView())) { + + // loop over all element vertices + int n = element.subEntities(dim); + for (int i = 0; i < n - 1; ++i) { + int globalI = this->problem().vertexMapper().subIndex(element, i, dim); + for (int j = i + 1; j < n; ++j) { + int globalJ = this->problem().vertexMapper().subIndex(element, j, dim); + // make sure that vertex j is in the neighbor set + // of vertex i and vice-versa + neighbors[globalI].insert(globalJ); + neighbors[globalJ].insert(globalI); + } + } + } + + // make vertices neighbors to themselfs + for (int i = 0; i < numVertices; ++i) + neighbors[i].insert(i); + + // allocate space for the rows of the matrix + for (int i = 0; i < numVertices; ++i) { + aBlocked_->setrowsize(i, neighbors[i].size()); + } + aBlocked_->endrowsizes(); + + // fill the rows with indices. each vertex talks to all of its + // neighbors. (it also talks to itself since vertices are + // sometimes quite egocentric.) + for (int i = 0; i < numVertices; ++i) { + auto nIt = neighbors[i].begin(); + const auto& nEndIt = neighbors[i].end(); + for (; nIt != nEndIt; ++nIt) { + aBlocked_->addindex(i, *nIt); + } + } + aBlocked_->endindices(); + } + + template <class FlatMatrix, class FlatVector> + void flatToBlocked_(const FlatMatrix& aFlat, + const FlatVector& xFlat, + const FlatVector& bFlat) + { + unsigned numBlocks = xBlocked_->size(); + static const unsigned numMassEq = numEq - dim; + for (unsigned rowBlockIdx = 0; rowBlockIdx < numBlocks; ++rowBlockIdx) + { + for (unsigned rowEqIdx = 0; rowEqIdx < numEq; ++rowEqIdx) + { + unsigned rowFlatIdx; + if (rowEqIdx < numMassEq) + rowFlatIdx = rowBlockIdx*numMassEq + rowEqIdx; + else + rowFlatIdx = numBlocks*numMassEq + rowBlockIdx*dim + rowEqIdx - numMassEq; + + (*xBlocked_)[rowBlockIdx][rowEqIdx] = xFlat[rowFlatIdx]; + (*bBlocked_)[rowBlockIdx][rowEqIdx] = bFlat[rowFlatIdx]; + + for (auto colBlockIt = (*aBlocked_)[rowBlockIdx].begin(); + colBlockIt != (*aBlocked_)[rowBlockIdx].end(); ++colBlockIt) + { + unsigned colBlockIdx = colBlockIt.index(); + auto& aBlock = (*aBlocked_)[rowBlockIdx][colBlockIdx]; + + for (unsigned colEqIdx = 0; colEqIdx < numEq; ++colEqIdx) + { + unsigned colFlatIdx; + if (colEqIdx < numMassEq) + colFlatIdx = colBlockIdx*numMassEq + colEqIdx; + else + colFlatIdx = numBlocks*numMassEq + colBlockIdx*dim + colEqIdx - numMassEq; + + aBlock[rowEqIdx][colEqIdx] = aFlat[rowFlatIdx][colFlatIdx]; + } + } + } + } + } + + template <class FlatVector> + void blockedToFlat_(FlatVector& xFlat, + FlatVector& bFlat) + { + unsigned numBlocks = xBlocked_->size(); + static const unsigned numMassEq = numEq - dim; + for (unsigned rowBlockIdx = 0; rowBlockIdx < numBlocks; ++rowBlockIdx) + { + for (unsigned rowEqIdx = 0; rowEqIdx < numEq; ++rowEqIdx) + { + unsigned rowFlatIdx; + if (rowEqIdx < numMassEq) + rowFlatIdx = rowBlockIdx*numMassEq + rowEqIdx; + else + rowFlatIdx = numBlocks*numMassEq + rowBlockIdx*dim + rowEqIdx - numMassEq; + + xFlat[rowFlatIdx] = (*xBlocked_)[rowBlockIdx][rowEqIdx]; + bFlat[rowFlatIdx] = (*bBlocked_)[rowBlockIdx][rowEqIdx]; + } + } + } + + std::shared_ptr<BlockMatrix> aBlocked_; + std::shared_ptr<BlockVector> xBlocked_; + std::shared_ptr<BlockVector> bBlocked_; +}; + +/*! + * \brief Wraps the AMG backend such that it can be used for the el2p model. + */ +template <class TypeTag> +class El2PAMGBackend : public El2PAMGBackendBase< + TypeTag, + Dune::Capabilities::canCommunicate<typename GET_PROP_TYPE(TypeTag, Grid), + GET_PROP_TYPE(TypeTag, Grid)::dimension>::v> +{ + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + enum { dofCodim = Grid::dimension }; + enum { isParallel = Dune::Capabilities::canCommunicate<Grid, dofCodim>::v }; + typedef El2PAMGBackendBase<TypeTag, isParallel> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + +public: + /*! + * \copydoc AMGBackend::AMGBackend() + */ + El2PAMGBackend(const Problem& problem) + : ParentType(problem) + {} +}; + +} // namespace Dumux + +#endif // DUMUX_EL2P_AMGBACKEND_HH diff --git a/dumux/geomechanics/el2p/assembler.hh b/dumux/geomechanics/el2p/assembler.hh new file mode 100644 index 0000000000000000000000000000000000000000..61cae074891f3636ddf4e5e4b0b83a065fefe597 --- /dev/null +++ b/dumux/geomechanics/el2p/assembler.hh @@ -0,0 +1,603 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * + * \brief This file contains an assembler for the Jacobian matrix + * of the two-phase linear-elastic model based on PDELab. + */ +#ifndef DUMUX_EL2P_ASSEMBLER_HH +#define DUMUX_EL2P_ASSEMBLER_HH + +#include "properties.hh" +#include "localoperator.hh" + +namespace Dumux { + +namespace Properties +{ +NEW_PROP_TAG(PressureFEM); //!< Finite element space used for pressure, saturation, ... +NEW_PROP_TAG(DisplacementFEM); //!< Finite element space used for displacement +NEW_PROP_TAG(PressureGridFunctionSpace); //!< Grid function space used for pressure, saturation, ... +NEW_PROP_TAG(DisplacementGridFunctionSpace); //!< Grid function space used for displacement +} + +namespace PDELab { + +/*! + * \brief An assembler for the Jacobian matrix + * of the two-phase linear-elastic model based on PDELab. + */ +template<class TypeTag> +class El2PAssembler +{ + typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; + typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; + + typedef typename GET_PROP_TYPE(TypeTag, PressureFEM) PressureFEM; + typedef typename GET_PROP_TYPE(TypeTag, PressureGridFunctionSpace) PressureGFS; + typedef typename PressureGFS::template Child<0>::Type PressureScalarGFS; + + typedef typename GET_PROP_TYPE(TypeTag, DisplacementFEM) DisplacementFEM; + typedef typename GET_PROP_TYPE(TypeTag, DisplacementGridFunctionSpace) DisplacementGFS; + typedef typename DisplacementGFS::template Child<0>::Type DisplacementScalarGFS; + + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; + typedef typename GET_PROP_TYPE(TypeTag, Constraints) Constraints; + typedef typename GET_PROP_TYPE(TypeTag, ConstraintsTrafo) ConstraintsTrafo; + typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LocalOperator; + typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + + enum{dim = GridView::dimension}; + typedef typename GridView::template Codim<0>::Entity Element; + + typedef typename GridView::template Codim<dim>::Entity Vertex; + + enum { + enablePartialReassemble = GET_PROP_VALUE(TypeTag, ImplicitEnablePartialReassemble), + enableJacobianRecycling = GET_PROP_VALUE(TypeTag, ImplicitEnableJacobianRecycling), + }; + + // copying the jacobian assembler is not a good idea + El2PAssembler(const El2PAssembler &); + +public: + /*! + * \brief The colors of elements and vertices required for partial + * Jacobian reassembly. + */ + enum EntityColor { + /*! + * Vertex/element that needs to be reassembled because some + * relative error is above the tolerance + */ + Red, + + /*! + * Vertex/element that needs to be reassembled because a + * neighboring element/vertex is red + */ + Yellow, + + /*! + * Yellow vertex has only non-green neighbor elements. + * + * This means that its relative error is below the tolerance, + * but its defect can be linearized without any additional + * cost. This is just an "internal" color which is not used + * ouside of the jacobian assembler. + */ + Orange, + + /*! + * Vertex/element that does not need to be reassembled + */ + Green + }; + + El2PAssembler() + { + // set reassemble tolerance to 0, so that if partial + // reassembly of the jacobian matrix is disabled, the + // reassemble tolerance is always smaller than the current + // relative tolerance + reassembleTolerance_ = 0.0; + } + + /*! + * \brief Initialize the jacobian assembler. + * + * At this point we can assume that all objects in the problem and + * the model have been allocated. We can not assume that they are + * fully initialized, though. + * + * \param problem The problem object + */ + void init(Problem& problem) + { + problemPtr_ = &problem; + + constraints_ = std::make_shared<Constraints>(); + + pressureFEM_ = std::make_shared<PressureFEM>(problemPtr_->gridView()); + pressureScalarGFS_ = std::make_shared<PressureScalarGFS>(problemPtr_->gridView(), *pressureFEM_, *constraints_); + pressureGFS_ = std::make_shared<PressureGFS>(*pressureScalarGFS_); + + displacementFEM_ = std::make_shared<DisplacementFEM>(problemPtr_->gridView()); + displacementScalarGFS_ = std::make_shared<DisplacementScalarGFS>(problemPtr_->gridView(), *displacementFEM_, *constraints_); + displacementGFS_ = std::make_shared<DisplacementGFS>(*displacementScalarGFS_); + + gridFunctionSpace_ = std::make_shared<GridFunctionSpace>(*pressureGFS_, *displacementGFS_); + + constraintsTrafo_ = std::make_shared<ConstraintsTrafo>(); + + // initialize the grid operator spaces + localOperator_ = std::make_shared<LocalOperator>(problemPtr_->model()); + gridOperator_ = + std::make_shared<GridOperator>(*gridFunctionSpace_, *constraintsTrafo_, + *gridFunctionSpace_, *constraintsTrafo_, *localOperator_); + + // allocate raw matrix + matrix_ = std::make_shared<JacobianMatrix>(*gridOperator_); + + // initialize the jacobian matrix and the right hand side + // vector + *matrix_ = 0; + reuseMatrix_ = false; + + residual_ = std::make_shared<SolutionVector>(*gridFunctionSpace_); + + int numVertices = gridView_().size(dim); + int numElements = gridView_().size(0); + + totalElems_ = gridView_().comm().sum(numElements); + + // initialize data needed for partial reassembly + if (enablePartialReassemble) { + vertexColor_.resize(numVertices); + vertexDelta_.resize(numVertices); + elementColor_.resize(numElements); + } + reassembleAll(); + } + + /*! + * \brief Assemble the local jacobian of the problem. + * + * The current state of affairs (esp. the previous and the current + * solutions) is represented by the model object. + */ + void assemble() + { + *matrix_ = 0; + gridOperator_->jacobian(problemPtr_->model().curSol(), *matrix_); + + *residual_ = 0; + gridOperator_->residual(problemPtr_->model().curSol(), *residual_); + + return; + } + + /*! + * \brief If Jacobian matrix recycling is enabled, this method + * specifies whether the next call to assemble() just + * rescales the storage term or does a full reassembly + * + * \param yesno If true, only rescale; else do full Jacobian assembly. + */ + void setMatrixReuseable(bool yesno = true) + { + if (enableJacobianRecycling) + reuseMatrix_ = yesno; + } + + /*! + * \brief If partial Jacobian matrix reassembly is enabled, this + * method causes all elements to be reassembled in the next + * assemble() call. + */ + void reassembleAll() + { + nextReassembleTolerance_ = 0.0; + + if (enablePartialReassemble) { + std::fill(vertexColor_.begin(), + vertexColor_.end(), + Red); + std::fill(elementColor_.begin(), + elementColor_.end(), + Red); + std::fill(vertexDelta_.begin(), + vertexDelta_.end(), + 0.0); + } + } + + /*! + * \brief Returns the relative error below which a vertex is + * considered to be "green" if partial Jacobian reassembly + * is enabled. + * + * This returns the _actual_ relative computed seen by + * computeColors(), not the tolerance which it was given. + */ + Scalar reassembleTolerance() const + { return reassembleTolerance_; } + + /*! + * \brief Update the distance where the non-linear system was + * originally insistently linearized and the point where it + * will be linerized the next time. + * + * This only has an effect if partial reassemble is enabled. + */ + void updateDiscrepancy(const SolutionVector &u, + const SolutionVector &uDelta) + { + if (!enablePartialReassemble) + return; + + // update the vector with the distances of the current + // evaluation point used for linearization from the original + // evaluation point + for (int i = 0; i < vertexDelta_.size(); ++i) { + PrimaryVariables uCurrent(u[i]); + PrimaryVariables uNext(uCurrent); + uNext -= uDelta[i]; + + // we need to add the distance the solution was moved for + // this vertex + Scalar dist = model_().relativeErrorVertex(i, + uCurrent, + uNext); + vertexDelta_[i] += std::abs(dist); + } + + } + + /*! + * \brief Determine the colors of vertices and elements for partial + * reassembly given a relative tolerance. + * + * The following approach is used: + * + * - Set all vertices and elements to 'green' + * - Mark all vertices as 'red' which exhibit an relative error above + * the tolerance + * - Mark all elements which feature a 'red' vetex as 'red' + * - Mark all vertices which are not 'red' and are part of a + * 'red' element as 'yellow' + * - Mark all elements which are not 'red' and contain a + * 'yellow' vertex as 'yellow' + * + * \param relTol The relative error below which a vertex won't be + * reassembled. Note that this specifies the + * worst-case relative error between the last + * linearization point and the current solution and + * _not_ the delta vector of the Newton iteration! + */ + void computeColors(Scalar relTol) + { + if (!enablePartialReassemble) + return; + + // mark the red vertices and update the tolerance of the + // linearization which actually will get achieved + nextReassembleTolerance_ = 0; + for (int i = 0; i < vertexColor_.size(); ++i) { + vertexColor_[i] = Green; + if (vertexDelta_[i] > relTol) { + // mark vertex as red if discrepancy is larger than + // the relative tolerance + vertexColor_[i] = Red; + } + nextReassembleTolerance_ = + std::max(nextReassembleTolerance_, vertexDelta_[i]); + }; + + // Mark all red elements + for (const auto& element : Dune::elements(gridView_())) { + // find out whether the current element features a red + // vertex + bool isRed = false; + int numVertices = element.subEntities(dim); + for (int i=0; i < numVertices; ++i) { + int globalI = vertexMapper_().subIndex(element, i, dim); + if (vertexColor_[globalI] == Red) { + isRed = true; + break; + } + }; + + // if yes, the element color is also red, else it is not + // red, i.e. green for the mean time + int eIdxGlobal = elementMapper_().index(element); + if (isRed) + elementColor_[eIdxGlobal] = Red; + else + elementColor_[eIdxGlobal] = Green; + } + + // Mark yellow vertices (as orange for the mean time) + for (const auto& element : Dune::elements(gridView_())) { + int eIdx = this->elementMapper_().index(element); + if (elementColor_[eIdx] != Red) + continue; // non-red elements do not tint vertices + // yellow! + + int numVertices = element.subEntities(dim); + for (int i=0; i < numVertices; ++i) { + int globalI = vertexMapper_().subIndex(element, i, dim); + // if a vertex is already red, don't recolor it to + // yellow! + if (vertexColor_[globalI] != Red) + vertexColor_[globalI] = Orange; + }; + } + + // Mark yellow elements + for (const auto& element : Dune::elements(gridView_())) { + int eIdx = this->elementMapper_().index(element); + if (elementColor_[eIdx] == Red) { + continue; // element is red already! + } + + // check whether the element features a yellow + // (resp. orange at this point) vertex + bool isYellow = false; + int numVertices = element.subEntities(dim); + for (int i=0; i < numVertices; ++i) { + int globalI = vertexMapper_().subIndex(element, i, dim); + if (vertexColor_[globalI] == Orange) { + isYellow = true; + break; + } + }; + + if (isYellow) + elementColor_[eIdx] = Yellow; + } + + // Demote orange vertices to yellow ones if it has at least + // one green element as a neighbor. + for (const auto& element : Dune::elements(gridView_())) { + int eIdx = this->elementMapper_().index(element); + if (elementColor_[eIdx] != Green) + continue; // yellow and red elements do not make + // orange vertices yellow! + + int numVertices = element.subEntities(dim); + for (int i=0; i < numVertices; ++i) { + int globalI = vertexMapper_().subIndex(element, i, dim); + // if a vertex is orange, recolor it to yellow! + if (vertexColor_[globalI] == Orange) + vertexColor_[globalI] = Yellow; + }; + } + + // promote the remaining orange vertices to red + for (int i=0; i < vertexColor_.size(); ++i) { + // if a vertex is green or yellow don't do anything! + if (vertexColor_[i] == Green || vertexColor_[i] == Yellow) + continue; + + // make sure the vertex is red (this is a no-op vertices + // which are already red!) + vertexColor_[i] = Red; + + // set the error of this vertex to 0 because the system + // will be consistently linearized at this vertex + vertexDelta_[i] = 0.0; + }; + }; + + /*! + * \brief Returns the reassemble color of a vertex + * + * \param element An element which contains the vertex + * \param vIdx The local index of the vertex in the element. + */ + int vertexColor(const Element &element, int vIdx) const + { + if (!enablePartialReassemble) + return Red; // reassemble unconditionally! + + int vIdxGlobal = vertexMapper_().subIndex(element, vIdx, dim); + + return vertexColor_[vIdxGlobal]; + } + + /*! + * \brief Returns the reassemble color of a vertex + * + * \param vIdxGlobal The global index of the vertex. + */ + int vertexColor(int vIdxGlobal) const + { + if (!enablePartialReassemble) + return Red; // reassemble unconditionally! + return vertexColor_[vIdxGlobal]; + } + + /*! + * \brief Returns the Jacobian reassemble color of an element + * + * \param element The Codim-0 DUNE entity + */ + int elementColor(const Element &element) const + { + if (!enablePartialReassemble) + return Red; // reassemble unconditionally! + + int eIdxGlobal = elementMapper_().index(element); + return elementColor_[eIdxGlobal]; + } + + /*! + * \brief Returns the Jacobian reassemble color of an element + * + * \param globalElementIdx The global index of the element. + */ + int elementColor(int globalElementIdx) const + { + if (!enablePartialReassemble) + return Red; // reassemble unconditionally! + return elementColor_[globalElementIdx]; + } + + /*! + * \brief Returns a pointer to the PDELab's grid function space. + */ + const GridFunctionSpace& gridFunctionSpace() const + { + return *gridFunctionSpace_; + } + + /*! + * \brief Returns a pointer to the PDELab's constraints + * transformation. + */ + const ConstraintsTrafo& constraintsTrafo() const + { + return *constraintsTrafo_; + } + + /*! + * \brief Return constant reference to global Jacobian matrix. + */ + const JacobianMatrix& matrix() const + { return *matrix_; } + + /*! + * \brief Return reference to global Jacobian matrix. + */ + JacobianMatrix& matrix() + { return *matrix_; } + + /*! + * \brief Return constant reference to global residual vector. + */ + const SolutionVector& residual() const + { return *residual_; } + + + /*! + * \brief Return reference to global residual vector. + */ + SolutionVector& residual() + { return *residual_; } + + const GridOperator &gridOperator() const + { return *gridOperator_;} + +private: + // reset the global linear system of equations. if partial + // reassemble is enabled, this means that the jacobian matrix must + // only be erased partially! + void resetSystem_() + { + // always reset the right hand side. + *residual_ = 0.0; + + if (!enablePartialReassemble) { + // If partial reassembly of the jacobian is not enabled, + // we can just reset everything! + (*matrix_) = 0; + return; + } + + // reset all entries corrosponding to a red vertex + for (int rowIdx = 0; rowIdx < matrix_->N(); ++rowIdx) { + if (vertexColor_[rowIdx] == Green) + continue; // the equations for this control volume are + // already below the treshold + + // set all entries in the row to 0 + typedef typename JacobianMatrix::ColIterator ColIterator; + ColIterator colIt = (*matrix_)[rowIdx].begin(); + const ColIterator &colEndIt = (*matrix_)[rowIdx].end(); + for (; colIt != colEndIt; ++colIt) { + (*colIt) = 0.0; + } + }; + } + + Problem &problem_() + { return *problemPtr_; } + const Problem &problem_() const + { return *problemPtr_; } + const Model &model_() const + { return problem_().model(); } + Model &model_() + { return problem_().model(); } + const GridView &gridView_() const + { return problem_().gridView(); } + const VertexMapper &vertexMapper_() const + { return problem_().vertexMapper(); } + const ElementMapper &elementMapper_() const + { return problem_().elementMapper(); } + + Problem *problemPtr_; + + // the jacobian matrix + std::shared_ptr<JacobianMatrix> matrix_; + // the right-hand side + std::shared_ptr<SolutionVector> residual_; + + // attributes required for jacobian matrix recycling + bool reuseMatrix_; + + // attributes required for partial jacobian reassembly + std::vector<EntityColor> vertexColor_; + std::vector<EntityColor> elementColor_; + std::vector<Scalar> vertexDelta_; + + int totalElems_; + int greenElems_; + + Scalar nextReassembleTolerance_; + Scalar reassembleTolerance_; + + + std::shared_ptr<Constraints> constraints_; + std::shared_ptr<PressureFEM> pressureFEM_; + std::shared_ptr<DisplacementFEM> displacementFEM_; + std::shared_ptr<PressureScalarGFS> pressureScalarGFS_; + std::shared_ptr<DisplacementScalarGFS> displacementScalarGFS_; + std::shared_ptr<PressureGFS> pressureGFS_; + std::shared_ptr<DisplacementGFS> displacementGFS_; + std::shared_ptr<GridFunctionSpace> gridFunctionSpace_; + std::shared_ptr<ConstraintsTrafo> constraintsTrafo_; + std::shared_ptr<LocalOperator> localOperator_; + std::shared_ptr<GridOperator> gridOperator_; +}; + +} // namespace PDELab + +} // namespace Dumux + +#endif diff --git a/dumux/geomechanics/el2p/basemodel.hh b/dumux/geomechanics/el2p/basemodel.hh new file mode 100644 index 0000000000000000000000000000000000000000..e79afb3c6ee5bd22e52e559663f4fdff999f8e35 --- /dev/null +++ b/dumux/geomechanics/el2p/basemodel.hh @@ -0,0 +1,984 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Base class for fully-implicit models + */ +#ifndef DUMUX_ELASTIC2P_BASE_MODEL_HH +#define DUMUX_ELASTIC2P_BASE_MODEL_HH + +#include <dune/geometry/type.hh> +#include <dune/istl/bvector.hh> + +#include <dumux/implicit/model.hh> +#include <dumux/common/valgrind.hh> +#include <dumux/parallel/vertexhandles.hh> + +namespace Dumux +{ + +/*! + * \ingroup ElTwoPBoxModel + * \brief base class for the two-phase geomechanics model + */ +template<class TypeTag> +class ElTwoPBaseModel +{ + typedef typename GET_PROP_TYPE(TypeTag, Model) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; + typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) JacobianAssembler; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + + enum { + numEq = GET_PROP_VALUE(TypeTag, NumEq), + dim = GridView::dimension + }; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, LocalJacobian) LocalJacobian; + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual; + typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod; + typedef typename GET_PROP_TYPE(TypeTag, NewtonController) NewtonController; + + typedef typename GridView::ctype CoordScalar; + typedef typename GridView::template Codim<0>::Entity Element; + + typedef typename Dune::ReferenceElements<CoordScalar, dim> ReferenceElements; + typedef typename Dune::ReferenceElement<CoordScalar, dim> ReferenceElement; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + + // copying a model is not a good idea + ElTwoPBaseModel(const ElTwoPBaseModel &); + +public: + /*! + * \brief The constructor. + */ + ElTwoPBaseModel() + : problemPtr_(0) + { + enableHints_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableHints); + } + + /*! + * \brief Apply the initial conditions to the model. + * + * \param problem The object representing the problem which needs to + * be simulated. + */ + void init(Problem &problem) + { + problemPtr_ = &problem; + + updateBoundaryIndices_(); + + int numDofs = asImp_().numDofs(); + if (isBox) + boxVolume_.resize(numDofs); + + localJacobian_.init(problem_()); + jacAsm_ = std::make_shared<JacobianAssembler>(); + jacAsm_->init(problem_()); + + uCur_ = std::make_shared<SolutionVector>(jacAsm_->gridFunctionSpace()); + uPrev_ = std::make_shared<SolutionVector>(jacAsm_->gridFunctionSpace()); + + asImp_().applyInitialSolution_(); + + // resize the hint vectors + if (isBox && enableHints_) { + int numVertices = gridView_().size(dim); + curHints_.resize(numVertices); + prevHints_.resize(numVertices); + hintsUsable_.resize(numVertices); + std::fill(hintsUsable_.begin(), + hintsUsable_.end(), + false); + } + + // also set the solution of the "previous" time step to the + // initial solution. + *uPrev_ = *uCur_; + } + + void setHints(const Element &element, + ElementVolumeVariables &prevVolVars, + ElementVolumeVariables &curVolVars) const + { + if (!isBox || !enableHints_) + return; + + int n = element.subEntities(dim); + prevVolVars.resize(n); + curVolVars.resize(n); + for (int i = 0; i < n; ++i) { + int vIdxGlobal = vertexMapper().subIndex(element, i, dim); + + if (!hintsUsable_[vIdxGlobal]) { + curVolVars[i].setHint(NULL); + prevVolVars[i].setHint(NULL); + } + else { + curVolVars[i].setHint(&curHints_[vIdxGlobal]); + prevVolVars[i].setHint(&prevHints_[vIdxGlobal]); + } + } + } + + void setHints(const Element &element, + ElementVolumeVariables &curVolVars) const + { + if (!isBox || !enableHints_) + return; + + int n = element.subEntities(dim); + curVolVars.resize(n); + for (int i = 0; i < n; ++i) { + int vIdxGlobal = vertexMapper().subIndex(element, i, dim); + + if (!hintsUsable_[vIdxGlobal]) + curVolVars[i].setHint(NULL); + else + curVolVars[i].setHint(&curHints_[vIdxGlobal]); + } + } + + void updatePrevHints() + { + if (!isBox || !enableHints_) + return; + + prevHints_ = curHints_; + } + + void updateCurHints(const Element &element, + const ElementVolumeVariables &elemVolVars) const + { + if (!isBox || !enableHints_) + return; + + for (unsigned int i = 0; i < elemVolVars.size(); ++i) { + int vIdxGlobal = vertexMapper().subIndex(element, i, dim); + curHints_[vIdxGlobal] = elemVolVars[i]; + if (!hintsUsable_[vIdxGlobal]) + prevHints_[vIdxGlobal] = elemVolVars[i]; + hintsUsable_[vIdxGlobal] = true; + } + } + + + /*! + * \brief Compute the global residual for an arbitrary solution + * vector. + * + * \param residual Stores the result + * \param u The solution for which the residual ought to be calculated + */ + Scalar globalResidual(SolutionVector &residual, + const SolutionVector &u) + { + jacAsm_->gridOperator().residual(u, residual); + + // calculate the square norm of the residual + Scalar result2 = residual.base().two_norm2(); + if (gridView_().comm().size() > 1) + result2 = gridView_().comm().sum(result2); + + // add up the residuals on the process borders + if (isBox && gridView_().comm().size() > 1) { + VertexHandleSum<PrimaryVariables, SolutionVector, VertexMapper> + sumHandle(residual, vertexMapper()); + gridView_().communicate(sumHandle, + Dune::InteriorBorder_InteriorBorder_Interface, + Dune::ForwardCommunication); + } + + return std::sqrt(result2); + } + + /*! + * \brief Compute the global residual for the current solution + * vector. + * + * \param residual Stores the result + */ + Scalar globalResidual(SolutionVector &residual) + { + return globalResidual(residual, curSol()); + } + + /*! + * \brief Compute the integral over the domain of the storage + * terms of all conservation quantities. + * + * \param storage Stores the result + */ + void globalStorage(PrimaryVariables &storage) + { + storage = 0; + + for (const auto& element : Dune::elements(gridView_())) + { + if(element.partitionType() == Dune::InteriorEntity) + { + localResidual().evalStorage(element); + + if (isBox) + { + for (int i = 0; i < element.subEntities(dim); ++i) + storage += localResidual().storageTerm()[i]; + } + else + { + storage += localResidual().storageTerm()[0]; + } + } + } + + if (gridView_().comm().size() > 1) + storage = gridView_().comm().sum(storage); + } + + /*! + * \brief Returns the volume \f$\mathrm{[m^3]}\f$ of a given control volume. + * + * \param vIdxGlobal The global index of the control volume's + * associated vertex + */ + Scalar boxVolume(const int vIdxGlobal) const + { + if (isBox) + { + return boxVolume_[vIdxGlobal][0]; + } + else + { + DUNE_THROW(Dune::InvalidStateException, + "requested box volume for cell-centered model"); + } + } + + /*! + * \brief Reference to the current solution as a block vector. + */ + const SolutionVector &curSol() const + { return *uCur_; } + + /*! + * \brief Reference to the current solution as a block vector. + */ + SolutionVector &curSol() + { return *uCur_; } + + /*! + * \brief Reference to the previous solution as a block vector. + */ + const SolutionVector &prevSol() const + { return *uPrev_; } + + /*! + * \brief Reference to the previous solution as a block vector. + */ + SolutionVector &prevSol() + { return *uPrev_; } + + /*! + * \brief Returns the operator assembler for the global jacobian of + * the problem. + */ + JacobianAssembler &jacobianAssembler() + { return *jacAsm_; } + + /*! + * \copydoc jacobianAssembler() + */ + const JacobianAssembler &jacobianAssembler() const + { return *jacAsm_; } + + /*! + * \brief Returns the local jacobian which calculates the local + * stiffness matrix for an arbitrary element. + * + * The local stiffness matrices of the element are used by + * the jacobian assembler to produce a global linerization of the + * problem. + */ + LocalJacobian &localJacobian() + { return localJacobian_; } + /*! + * \copydoc localJacobian() + */ + const LocalJacobian &localJacobian() const + { return localJacobian_; } + + /*! + * \brief Returns the local residual function. + */ + LocalResidual &localResidual() + { return localJacobian().localResidual(); } + /*! + * \copydoc localResidual() + */ + const LocalResidual &localResidual() const + { return localJacobian().localResidual(); } + + /*! + * \brief Returns the maximum relative shift between two vectors of + * primary variables. + * + * \param priVars1 The first vector of primary variables + * \param priVars2 The second vector of primary variables + */ + Scalar relativeShiftAtDof(const PrimaryVariables &priVars1, + const PrimaryVariables &priVars2) + { + Scalar result = 0.0; + for (int j = 0; j < numEq; ++j) { + Scalar eqErr = std::abs(priVars1[j] - priVars2[j]); + eqErr /= std::max<Scalar>(1.0, std::abs(priVars1[j] + priVars2[j])/2); + + result = std::max(result, eqErr); + } + return result; + } + + /*! + * \brief Try to progress the model to the next timestep. + * + * \param solver The non-linear solver + * \param controller The controller which specifies the behaviour + * of the non-linear solver + */ + bool update(NewtonMethod &solver, + NewtonController &controller) + { +#if HAVE_VALGRIND + for (size_t i = 0; i < curSol().base().size(); ++i) + Valgrind::CheckDefined(curSol().base()[i]); +#endif // HAVE_VALGRIND + + asImp_().updateBegin(); + + bool converged = solver.execute(controller); + if (converged) { + asImp_().updateSuccessful(); + } + else + asImp_().updateFailed(); + +#if HAVE_VALGRIND + for (size_t i = 0; i < curSol().base().size(); ++i) { + Valgrind::CheckDefined(curSol().base()[i]); + } +#endif // HAVE_VALGRIND + + return converged; + } + + /*! + * \brief Check the plausibility of the current solution + * + * This has to be done by the actual model, it knows + * best, what (ranges of) variables to check. + * This is primarily a hook + * which the actual model can overload. + */ + void checkPlausibility() const + { } + + /*! + * \brief Called by the update() method before it tries to + * apply the newton method. This is primarily a hook + * which the actual model can overload. + */ + void updateBegin() + { } + + + /*! + * \brief Called by the update() method if it was + * successful. This is primarily a hook which the actual + * model can overload. + */ + void updateSuccessful() + { } + + /*! + * \brief Called by the update() method if it was + * unsuccessful. This is primarily a hook which the actual + * model can overload. + */ + void updateFailed() + { + // Reset the current solution to the one of the + // previous time step so that we can start the next + // update at a physically meaningful solution. + *uCur_ = *uPrev_; + if (isBox) + curHints_ = prevHints_; + + jacAsm_->reassembleAll(); + } + + /*! + * \brief Called by the problem if a time integration was + * successful, post processing of the solution is done and + * the result has been written to disk. + * + * This should prepare the model for the next time integration. + */ + void advanceTimeLevel() + { + // make the current solution the previous one. + *uPrev_ = *uCur_; + if (isBox) + prevHints_ = curHints_; + + updatePrevHints(); + } + + /*! + * \brief Serializes the current state of the model. + * + * \tparam Restarter The type of the serializer class + * + * \param res The serializer object + */ + template <class Restarter> + void serialize(Restarter &res) + { + if (isBox) + res.template serializeEntities<dim>(asImp_(), gridView_()); + else + res.template serializeEntities<0>(asImp_(), gridView_()); + } + + /*! + * \brief Deserializes the state of the model. + * + * \tparam Restarter The type of the serializer class + * + * \param res The serializer object + */ + template <class Restarter> + void deserialize(Restarter &res) + { + if (isBox) + res.template deserializeEntities<dim>(asImp_(), gridView_()); + else + res.template deserializeEntities<0>(asImp_(), gridView_()); + + prevSol() = curSol(); + } + + /*! + * \brief Write the current solution for a vertex to a restart + * file. + * + * \param outstream The stream into which the vertex data should + * be serialized to + * \param entity The entity which's data should be + * serialized, i.e. a vertex for the box method + * and an element for the cell-centered method + */ + template <class Entity> + void serializeEntity(std::ostream &outstream, + const Entity &entity) + { + int dofIdxGlobal = dofMapper().index(entity); + + // write phase state + if (!outstream.good()) { + DUNE_THROW(Dune::IOError, + "Could not serialize vertex " + << dofIdxGlobal); + } + + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { + outstream << curSol()[dofIdxGlobal][eqIdx] << " "; + } + } + + /*! + * \brief Reads the current solution variables for a vertex from a + * restart file. + * + * \param instream The stream from which the vertex data should + * be deserialized from + * \param entity The entity which's data should be + * serialized, i.e. a vertex for the box method + * and an element for the cell-centered method + */ + template <class Entity> + void deserializeEntity(std::istream &instream, + const Entity &entity) + { + int dofIdxGlobal = dofMapper().index(entity); + + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { + if (!instream.good()) + DUNE_THROW(Dune::IOError, + "Could not deserialize vertex " + << dofIdxGlobal); + instream >> curSol()[dofIdxGlobal][eqIdx]; + } + } + + /*! + * \brief Returns the number of global degrees of freedoms (DOFs) + */ + size_t numDofs() const + { + if (isBox) + return gridView_().size(dim); + else + return gridView_().size(0); + } + + /*! + * \brief Mapper for the entities where degrees of freedoms are + * defined to indices. + * + * Is the box method is used, this means a mapper + * for vertices, if the cell centered method is used, + * this means a mapper for elements. + */ + template <class T = TypeTag> + const typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox), VertexMapper>::type &dofMapper() const + { + return problem_().vertexMapper(); + } + template <class T = TypeTag> + const typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox), ElementMapper>::type &dofMapper() const + { + return problem_().elementMapper(); + } + + /*! + * \brief Mapper for vertices to indices. + */ + const VertexMapper &vertexMapper() const + { return problem_().vertexMapper(); } + + /*! + * \brief Mapper for elements to indices. + */ + const ElementMapper &elementMapper() const + { return problem_().elementMapper(); } + + /*! + * \brief Resets the Jacobian matrix assembler, so that the + * boundary types can be altered. + */ + void resetJacobianAssembler () + { + jacAsm_.template reset<JacobianAssembler>(0); + jacAsm_ = std::make_shared<JacobianAssembler>(); + jacAsm_->init(problem_()); + } + + /*! + * \brief Update the weights of all primary variables within an + * element given the complete set of volume variables + * + * \param element The DUNE codim 0 entity + * \param volVars All volume variables for the element + */ + void updatePVWeights(const Element &element, + const ElementVolumeVariables &volVars) const + { } + + /*! + * \brief Add the vector fields for analysing the convergence of + * the newton method to the a VTK multi writer. + * + * \tparam MultiWriter The type of the VTK multi writer + * + * \param writer The VTK multi writer object on which the fields should be added. + * \param u The solution function + * \param deltaU The delta of the solution function before and after the Newton update + */ + template <class MultiWriter> + void addConvergenceVtkFields(MultiWriter &writer, + const SolutionVector &u, + const SolutionVector &deltaU) + { + typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; + + SolutionVector residual(u); + asImp_().globalResidual(residual, u); + + // create the required scalar fields + unsigned numDofs = asImp_().numDofs(); + + // global defect of the two auxiliary equations + ScalarField* def[numEq]; + ScalarField* delta[numEq]; + ScalarField* x[numEq]; + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { + x[eqIdx] = writer.allocateManagedBuffer(numDofs); + delta[eqIdx] = writer.allocateManagedBuffer(numDofs); + def[eqIdx] = writer.allocateManagedBuffer(numDofs); + } + + for (unsigned int vIdxGlobal = 0; vIdxGlobal < u.base().size(); vIdxGlobal++) + { + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + { + (*x[eqIdx])[vIdxGlobal] = u.base()[vIdxGlobal][eqIdx]; + (*delta[eqIdx])[vIdxGlobal] = - deltaU.base()[vIdxGlobal][eqIdx]; + (*def[eqIdx])[vIdxGlobal] = residual.base()[vIdxGlobal][eqIdx]; + } + } + + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { + std::ostringstream oss; + oss.str(""); oss << "x_" << eqIdx; + if (isBox) + writer.attachVertexData(*x[eqIdx], oss.str()); + else + writer.attachCellData(*x[eqIdx], oss.str()); + oss.str(""); oss << "delta_" << eqIdx; + if (isBox) + writer.attachVertexData(*delta[eqIdx], oss.str()); + else + writer.attachCellData(*delta[eqIdx], oss.str()); + oss.str(""); oss << "defect_" << eqIdx; + if (isBox) + writer.attachVertexData(*def[eqIdx], oss.str()); + else + writer.attachCellData(*def[eqIdx], oss.str()); + } + + asImp_().addOutputVtkFields(u, writer); + } + + /*! + * \brief Add the quantities of a time step which ought to be written to disk. + * + * This should be overwritten by the actual model if any secondary + * variables should be written out. Read: This should _always_ be + * overwritten by well behaved models! + * + * \tparam MultiWriter The type of the VTK multi writer + * + * \param sol The global vector of primary variable values. + * \param writer The VTK multi writer where the fields should be added. + */ + template <class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, + MultiWriter &writer) + { + typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; + + // create the required scalar fields + unsigned numDofs = asImp_().numDofs(); + + // global defect of the two auxiliary equations + ScalarField* x[numEq]; + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { + x[eqIdx] = writer.allocateManagedBuffer(numDofs); + } + + for (int vIdxGlobal = 0; vIdxGlobal < sol.size(); vIdxGlobal++) + { + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { + (*x[eqIdx])[vIdxGlobal] = sol[vIdxGlobal][eqIdx]; + } + } + + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { + std::ostringstream oss; + oss << "primaryVar_" << eqIdx; + if (isBox) + writer.attachVertexData(*x[eqIdx], oss.str()); + else + writer.attachCellData(*x[eqIdx], oss.str()); + } + } + + /*! + * \brief Reference to the grid view of the spatial domain. + */ + const GridView &gridView() const + { return problem_().gridView(); } + + /*! + * \brief Returns true if the entity indicated by 'dofIdxGlobal' + * is located on / touches the grid's boundary. + * + * \param dofIdxGlobal The global index of the entity + */ + bool onBoundary(const int dofIdxGlobal) const + { return boundaryIndices_[dofIdxGlobal]; } + + /*! + * \brief Returns true if a vertex is located on the grid's + * boundary. + * + * \param element A DUNE Codim<0> entity which contains the control + * volume's associated vertex. + * \param vIdx The local vertex index inside element + */ + bool onBoundary(const Element &element, const int vIdx) const + { + if (isBox) + return onBoundary(vertexMapper().subIndex(element, vIdx, dim)); + else + DUNE_THROW(Dune::InvalidStateException, + "requested for cell-centered model"); + } + + + /*! + * \brief Returns true if the control volume touches + * the grid's boundary. + * + * \param element A DUNE Codim<0> entity coinciding with the control + * volume. + */ + bool onBoundary(const Element &element) const + { + if (!isBox) + return onBoundary(elementMapper().index(element)); + else + DUNE_THROW(Dune::InvalidStateException, + "requested for box model"); + } + + /*! + * \brief Fill the fluid state according to the primary variables. + * + * Taking the information from the primary variables, + * the fluid state is filled with every information that is + * necessary to evaluate the model's local residual. + * + * \param priVars The primary variables of the model. + * \param problem The problem at hand. + * \param element The current element. + * \param fvGeometry The finite volume element geometry. + * \param scvIdx The index of the subcontrol volume. + * \param fluidState The fluid state to fill. + */ + template <class FluidState> + static void completeFluidState(const PrimaryVariables& priVars, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const int scvIdx, + FluidState& fluidState) + { + VolumeVariables::completeFluidState(priVars, problem, element, + fvGeometry, scvIdx, fluidState); + } +protected: + /*! + * \brief A reference to the problem on which the model is applied. + */ + Problem &problem_() + { return *problemPtr_; } + /*! + * \copydoc problem_() + */ + const Problem &problem_() const + { return *problemPtr_; } + + /*! + * \brief Reference to the grid view of the spatial domain. + */ + const GridView &gridView_() const + { return problem_().gridView(); } + + /*! + * \brief Reference to the local residal object + */ + LocalResidual &localResidual_() + { return localJacobian_.localResidual(); } + + /*! + * \brief Applies the initial solution for all vertices of the grid. + */ + void applyInitialSolution_() + { + // first set the whole domain to zero + *uCur_ = Scalar(0.0); + boxVolume_ = Scalar(0.0); + + FVElementGeometry fvGeometry; + + // iterate through leaf grid and evaluate initial + // condition at the center of each sub control volume + // + // TODO: the initial condition needs to be unique for + // each vertex. we should think about the API... + for (const auto& element : Dune::elements(gridView_())) { + // deal with the current element + fvGeometry.update(gridView_(), element); + + // loop over all element vertices, i.e. sub control volumes + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; scvIdx++) + { + // get the global index of the degree of freedom + int dofIdxGlobal = dofMapper().subIndex(element, scvIdx, dofCodim); + + // let the problem do the dirty work of nailing down + // the initial solution. + PrimaryVariables initPriVars; + Valgrind::SetUndefined(initPriVars); + problem_().initial(initPriVars, + element, + fvGeometry, + scvIdx); + Valgrind::CheckDefined(initPriVars); + + if (isBox) + { + // add up the initial values of all sub-control + // volumes. If the initial values disagree for + // different sub control volumes, the initial value + // will be the arithmetic mean. + initPriVars *= fvGeometry.subContVol[scvIdx].volume; + boxVolume_[dofIdxGlobal] += fvGeometry.subContVol[scvIdx].volume; + } + + uCur_->base()[dofIdxGlobal] += initPriVars; + Valgrind::CheckDefined(uCur_->base()[dofIdxGlobal]); + } + } + + // add up the primary variables and the volumes of the boxes + // which cross process borders + if (isBox && gridView_().comm().size() > 1) { + VertexHandleSum<Dune::FieldVector<Scalar, 1>, + Dune::BlockVector<Dune::FieldVector<Scalar, 1> >, + VertexMapper> sumVolumeHandle(boxVolume_, vertexMapper()); + gridView_().communicate(sumVolumeHandle, + Dune::InteriorBorder_InteriorBorder_Interface, + Dune::ForwardCommunication); + + VertexHandleSum<PrimaryVariables, SolutionVector, VertexMapper> + sumPVHandle(uCur_->base(), vertexMapper()); + gridView_().communicate(sumPVHandle, + Dune::InteriorBorder_InteriorBorder_Interface, + Dune::ForwardCommunication); + } + + if (isBox) + { + // divide all primary variables by the volume of their boxes + for (unsigned int i = 0; i < uCur_->base().size(); ++i) { + uCur_->base()[i] /= boxVolume(i); + } + } + } + + /*! + * \brief Find all indices of boundary vertices (box) / elements (cell centered). + */ + void updateBoundaryIndices_() + { + boundaryIndices_.resize(numDofs()); + std::fill(boundaryIndices_.begin(), boundaryIndices_.end(), false); + + for (const auto& element : Dune::elements(gridView_())) { + Dune::GeometryType geomType = element.geometry().type(); + const ReferenceElement &refElement = ReferenceElements::general(geomType); + + for (const auto& intersection : Dune::intersections(gridView_(), element)) { + if (intersection.boundary()) { + if (isBox) + { + // add all vertices on the intersection to the set of + // boundary vertices + int fIdx = intersection.indexInInside(); + int numFaceVerts = refElement.size(fIdx, 1, dim); + for (int faceVertexIdx = 0; + faceVertexIdx < numFaceVerts; + ++faceVertexIdx) + { + int vIdx = refElement.subEntity(fIdx, + 1, + faceVertexIdx, + dim); + int vIdxGlobal = vertexMapper().subIndex(element, vIdx, dim); + boundaryIndices_[vIdxGlobal] = true; + } + } + else + { + int eIdxGlobal = elementMapper().index(element); + boundaryIndices_[eIdxGlobal] = true; + } + } + } + } + } + + // the hint cache for the previous and the current volume + // variables + mutable std::vector<bool> hintsUsable_; + mutable std::vector<VolumeVariables> curHints_; + mutable std::vector<VolumeVariables> prevHints_; + + // the problem we want to solve. defines the constitutive + // relations, matxerial laws, etc. + Problem *problemPtr_; + + // calculates the local jacobian matrix for a given element + LocalJacobian localJacobian_; + // Linearizes the problem at the current time step using the + // local jacobian + std::shared_ptr<JacobianAssembler> jacAsm_; + + // the set of all indices of vertices on the boundary + std::vector<bool> boundaryIndices_; + + // cur is the current iterative solution, prev the converged + // solution of the previous time step + std::shared_ptr<SolutionVector> uCur_; + std::shared_ptr<SolutionVector> uPrev_; + + Dune::BlockVector<Dune::FieldVector<Scalar, 1> > boxVolume_; + +private: + /*! + * \brief Returns whether messages should be printed + */ + bool verbose_() const + { return gridView_().comm().rank() == 0; } + + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } + + bool enableHints_; +}; +} // end namespace Dumux + +#endif diff --git a/dumux/geomechanics/el2p/el2pamgbackend.hh b/dumux/geomechanics/el2p/el2pamgbackend.hh index 1a8a04d6c76925f557ae13d4b9986cf6b751448f..a0de251574a94418d2789cbd7472fb4872bb45f0 100644 --- a/dumux/geomechanics/el2p/el2pamgbackend.hh +++ b/dumux/geomechanics/el2p/el2pamgbackend.hh @@ -1,235 +1,8 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * See the file COPYING for full copying permissions. * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -/*! - * \file - * \ingroup Linear - * - * \brief Wraps the AMG backend such that it can be used for the el2p model. - */ -#ifndef DUMUX_EL2P_AMGBACKEND_HH -#define DUMUX_EL2P_AMGBACKEND_HH +#ifndef DUMUX_EL2P_AMGBACKEND_HH_OLD +#define DUMUX_EL2P_AMGBACKEND_HH_OLD -#include <dumux/linear/amgbackend.hh> +#warning this header is deprecated, use dumux/geomechanics/el2p/amgbackend.hh instead -namespace Dumux { +#include <dumux/geomechanics/el2p/amgbackend.hh> -/*! - * \brief Base class for the ElTwoP AMGBackend. - */ -template <class TypeTag, bool isParallel> -class El2PAMGBackendBase : public AMGBackend<TypeTag> -{ - typedef AMGBackend<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - -public: - /*! - * \copydoc AMGBackend::AMGBackend() - */ - El2PAMGBackendBase(const Problem& problem) - : ParentType(problem) - {} -}; - -/*! - * \brief Specialization for the parallel setting. - */ -template <class TypeTag> -class El2PAMGBackendBase<TypeTag, true> : public AMGBackend<TypeTag> -{ - typedef AMGBackend<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; - typedef typename Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; - typedef typename Dune::BCRSMatrix<MatrixBlock> BlockMatrix; - typedef typename Dune::FieldVector<Scalar, numEq> VectorBlock; - typedef typename Dune::BlockVector<VectorBlock> BlockVector; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum { dim = GridView::dimension }; - -public: - /*! - * \copydoc AMGBackend::AMGBackend() - */ - El2PAMGBackendBase(const Problem& problem) - : ParentType(problem) - { - createBlockMatrixAndVectors_(); - } - - /*! - * \copydoc AMGBackend::solve() - */ - template<class Matrix, class Vector> - bool solve(Matrix& A, Vector& x, Vector& b) - { - flatToBlocked_(A, x, b); - int converged = ParentType::solve(*aBlocked_, *xBlocked_, *bBlocked_); - blockedToFlat_(x, b); - return converged; - } - -private: - void createBlockMatrixAndVectors_() - { - int numVertices = this->problem().gridView().size(dim); - - aBlocked_ = std::make_shared<BlockMatrix>(numVertices, numVertices, BlockMatrix::random); - xBlocked_ = std::make_shared<BlockVector>(numVertices); - bBlocked_ = std::make_shared<BlockVector>(numVertices); - - // find out the global indices of the neighboring vertices of - // each vertex - typedef std::set<int> NeighborSet; - std::vector<NeighborSet> neighbors(numVertices); - for (const auto& element : Dune::elements(this->problem().gridView())) { - - // loop over all element vertices - int n = element.subEntities(dim); - for (int i = 0; i < n - 1; ++i) { - int globalI = this->problem().vertexMapper().subIndex(element, i, dim); - for (int j = i + 1; j < n; ++j) { - int globalJ = this->problem().vertexMapper().subIndex(element, j, dim); - // make sure that vertex j is in the neighbor set - // of vertex i and vice-versa - neighbors[globalI].insert(globalJ); - neighbors[globalJ].insert(globalI); - } - } - } - - // make vertices neighbors to themselfs - for (int i = 0; i < numVertices; ++i) - neighbors[i].insert(i); - - // allocate space for the rows of the matrix - for (int i = 0; i < numVertices; ++i) { - aBlocked_->setrowsize(i, neighbors[i].size()); - } - aBlocked_->endrowsizes(); - - // fill the rows with indices. each vertex talks to all of its - // neighbors. (it also talks to itself since vertices are - // sometimes quite egocentric.) - for (int i = 0; i < numVertices; ++i) { - auto nIt = neighbors[i].begin(); - const auto& nEndIt = neighbors[i].end(); - for (; nIt != nEndIt; ++nIt) { - aBlocked_->addindex(i, *nIt); - } - } - aBlocked_->endindices(); - } - - template <class FlatMatrix, class FlatVector> - void flatToBlocked_(const FlatMatrix& aFlat, - const FlatVector& xFlat, - const FlatVector& bFlat) - { - unsigned numBlocks = xBlocked_->size(); - static const unsigned numMassEq = numEq - dim; - for (unsigned rowBlockIdx = 0; rowBlockIdx < numBlocks; ++rowBlockIdx) - { - for (unsigned rowEqIdx = 0; rowEqIdx < numEq; ++rowEqIdx) - { - unsigned rowFlatIdx; - if (rowEqIdx < numMassEq) - rowFlatIdx = rowBlockIdx*numMassEq + rowEqIdx; - else - rowFlatIdx = numBlocks*numMassEq + rowBlockIdx*dim + rowEqIdx - numMassEq; - - (*xBlocked_)[rowBlockIdx][rowEqIdx] = xFlat[rowFlatIdx]; - (*bBlocked_)[rowBlockIdx][rowEqIdx] = bFlat[rowFlatIdx]; - - for (auto colBlockIt = (*aBlocked_)[rowBlockIdx].begin(); - colBlockIt != (*aBlocked_)[rowBlockIdx].end(); ++colBlockIt) - { - unsigned colBlockIdx = colBlockIt.index(); - auto& aBlock = (*aBlocked_)[rowBlockIdx][colBlockIdx]; - - for (unsigned colEqIdx = 0; colEqIdx < numEq; ++colEqIdx) - { - unsigned colFlatIdx; - if (colEqIdx < numMassEq) - colFlatIdx = colBlockIdx*numMassEq + colEqIdx; - else - colFlatIdx = numBlocks*numMassEq + colBlockIdx*dim + colEqIdx - numMassEq; - - aBlock[rowEqIdx][colEqIdx] = aFlat[rowFlatIdx][colFlatIdx]; - } - } - } - } - } - - template <class FlatVector> - void blockedToFlat_(FlatVector& xFlat, - FlatVector& bFlat) - { - unsigned numBlocks = xBlocked_->size(); - static const unsigned numMassEq = numEq - dim; - for (unsigned rowBlockIdx = 0; rowBlockIdx < numBlocks; ++rowBlockIdx) - { - for (unsigned rowEqIdx = 0; rowEqIdx < numEq; ++rowEqIdx) - { - unsigned rowFlatIdx; - if (rowEqIdx < numMassEq) - rowFlatIdx = rowBlockIdx*numMassEq + rowEqIdx; - else - rowFlatIdx = numBlocks*numMassEq + rowBlockIdx*dim + rowEqIdx - numMassEq; - - xFlat[rowFlatIdx] = (*xBlocked_)[rowBlockIdx][rowEqIdx]; - bFlat[rowFlatIdx] = (*bBlocked_)[rowBlockIdx][rowEqIdx]; - } - } - } - - std::shared_ptr<BlockMatrix> aBlocked_; - std::shared_ptr<BlockVector> xBlocked_; - std::shared_ptr<BlockVector> bBlocked_; -}; - -/*! - * \brief Wraps the AMG backend such that it can be used for the el2p model. - */ -template <class TypeTag> -class El2PAMGBackend : public El2PAMGBackendBase< - TypeTag, - Dune::Capabilities::canCommunicate<typename GET_PROP_TYPE(TypeTag, Grid), - GET_PROP_TYPE(TypeTag, Grid)::dimension>::v> -{ - typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; - enum { dofCodim = Grid::dimension }; - enum { isParallel = Dune::Capabilities::canCommunicate<Grid, dofCodim>::v }; - typedef El2PAMGBackendBase<TypeTag, isParallel> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - -public: - /*! - * \copydoc AMGBackend::AMGBackend() - */ - El2PAMGBackend(const Problem& problem) - : ParentType(problem) - {} -}; - -} // namespace Dumux - -#endif // DUMUX_EL2P_AMGBACKEND_HH +#endif diff --git a/dumux/geomechanics/el2p/el2passembler.hh b/dumux/geomechanics/el2p/el2passembler.hh index 060aa29d98034941714fafeed45b4e8039b33339..bdf94c449faa5dde4b113888ee5868b6f0480e22 100644 --- a/dumux/geomechanics/el2p/el2passembler.hh +++ b/dumux/geomechanics/el2p/el2passembler.hh @@ -1,603 +1,8 @@ -// -*- 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 This file contains an assembler for the Jacobian matrix - * of the two-phase linear-elastic model based on PDELab. - */ -#ifndef DUMUX_EL2P_ASSEMBLER_HH -#define DUMUX_EL2P_ASSEMBLER_HH +#ifndef DUMUX_EL2P_ASSEMBLER_HH_OLD +#define DUMUX_EL2P_ASSEMBLER_HH_OLD -#include "el2pproperties.hh" -#include "el2plocaloperator.hh" +#warning this header is deprecated, use dumux/geomechanics/el2p/assembler.hh instead -namespace Dumux { - -namespace Properties -{ -NEW_PROP_TAG(PressureFEM); //!< Finite element space used for pressure, saturation, ... -NEW_PROP_TAG(DisplacementFEM); //!< Finite element space used for displacement -NEW_PROP_TAG(PressureGridFunctionSpace); //!< Grid function space used for pressure, saturation, ... -NEW_PROP_TAG(DisplacementGridFunctionSpace); //!< Grid function space used for displacement -} - -namespace PDELab { - -/*! - * \brief An assembler for the Jacobian matrix - * of the two-phase linear-elastic model based on PDELab. - */ -template<class TypeTag> -class El2PAssembler -{ - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; - - typedef typename GET_PROP_TYPE(TypeTag, PressureFEM) PressureFEM; - typedef typename GET_PROP_TYPE(TypeTag, PressureGridFunctionSpace) PressureGFS; - typedef typename PressureGFS::template Child<0>::Type PressureScalarGFS; - - typedef typename GET_PROP_TYPE(TypeTag, DisplacementFEM) DisplacementFEM; - typedef typename GET_PROP_TYPE(TypeTag, DisplacementGridFunctionSpace) DisplacementGFS; - typedef typename DisplacementGFS::template Child<0>::Type DisplacementScalarGFS; - - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; - typedef typename GET_PROP_TYPE(TypeTag, Constraints) Constraints; - typedef typename GET_PROP_TYPE(TypeTag, ConstraintsTrafo) ConstraintsTrafo; - typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LocalOperator; - typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; - - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - - enum{dim = GridView::dimension}; - typedef typename GridView::template Codim<0>::Entity Element; - - typedef typename GridView::template Codim<dim>::Entity Vertex; - - enum { - enablePartialReassemble = GET_PROP_VALUE(TypeTag, ImplicitEnablePartialReassemble), - enableJacobianRecycling = GET_PROP_VALUE(TypeTag, ImplicitEnableJacobianRecycling), - }; - - // copying the jacobian assembler is not a good idea - El2PAssembler(const El2PAssembler &); - -public: - /*! - * \brief The colors of elements and vertices required for partial - * Jacobian reassembly. - */ - enum EntityColor { - /*! - * Vertex/element that needs to be reassembled because some - * relative error is above the tolerance - */ - Red, - - /*! - * Vertex/element that needs to be reassembled because a - * neighboring element/vertex is red - */ - Yellow, - - /*! - * Yellow vertex has only non-green neighbor elements. - * - * This means that its relative error is below the tolerance, - * but its defect can be linearized without any additional - * cost. This is just an "internal" color which is not used - * ouside of the jacobian assembler. - */ - Orange, - - /*! - * Vertex/element that does not need to be reassembled - */ - Green - }; - - El2PAssembler() - { - // set reassemble tolerance to 0, so that if partial - // reassembly of the jacobian matrix is disabled, the - // reassemble tolerance is always smaller than the current - // relative tolerance - reassembleTolerance_ = 0.0; - } - - /*! - * \brief Initialize the jacobian assembler. - * - * At this point we can assume that all objects in the problem and - * the model have been allocated. We can not assume that they are - * fully initialized, though. - * - * \param problem The problem object - */ - void init(Problem& problem) - { - problemPtr_ = &problem; - - constraints_ = std::make_shared<Constraints>(); - - pressureFEM_ = std::make_shared<PressureFEM>(problemPtr_->gridView()); - pressureScalarGFS_ = std::make_shared<PressureScalarGFS>(problemPtr_->gridView(), *pressureFEM_, *constraints_); - pressureGFS_ = std::make_shared<PressureGFS>(*pressureScalarGFS_); - - displacementFEM_ = std::make_shared<DisplacementFEM>(problemPtr_->gridView()); - displacementScalarGFS_ = std::make_shared<DisplacementScalarGFS>(problemPtr_->gridView(), *displacementFEM_, *constraints_); - displacementGFS_ = std::make_shared<DisplacementGFS>(*displacementScalarGFS_); - - gridFunctionSpace_ = std::make_shared<GridFunctionSpace>(*pressureGFS_, *displacementGFS_); - - constraintsTrafo_ = std::make_shared<ConstraintsTrafo>(); - - // initialize the grid operator spaces - localOperator_ = std::make_shared<LocalOperator>(problemPtr_->model()); - gridOperator_ = - std::make_shared<GridOperator>(*gridFunctionSpace_, *constraintsTrafo_, - *gridFunctionSpace_, *constraintsTrafo_, *localOperator_); - - // allocate raw matrix - matrix_ = std::make_shared<JacobianMatrix>(*gridOperator_); - - // initialize the jacobian matrix and the right hand side - // vector - *matrix_ = 0; - reuseMatrix_ = false; - - residual_ = std::make_shared<SolutionVector>(*gridFunctionSpace_); - - int numVertices = gridView_().size(dim); - int numElements = gridView_().size(0); - - totalElems_ = gridView_().comm().sum(numElements); - - // initialize data needed for partial reassembly - if (enablePartialReassemble) { - vertexColor_.resize(numVertices); - vertexDelta_.resize(numVertices); - elementColor_.resize(numElements); - } - reassembleAll(); - } - - /*! - * \brief Assemble the local jacobian of the problem. - * - * The current state of affairs (esp. the previous and the current - * solutions) is represented by the model object. - */ - void assemble() - { - *matrix_ = 0; - gridOperator_->jacobian(problemPtr_->model().curSol(), *matrix_); - - *residual_ = 0; - gridOperator_->residual(problemPtr_->model().curSol(), *residual_); - - return; - } - - /*! - * \brief If Jacobian matrix recycling is enabled, this method - * specifies whether the next call to assemble() just - * rescales the storage term or does a full reassembly - * - * \param yesno If true, only rescale; else do full Jacobian assembly. - */ - void setMatrixReuseable(bool yesno = true) - { - if (enableJacobianRecycling) - reuseMatrix_ = yesno; - } - - /*! - * \brief If partial Jacobian matrix reassembly is enabled, this - * method causes all elements to be reassembled in the next - * assemble() call. - */ - void reassembleAll() - { - nextReassembleTolerance_ = 0.0; - - if (enablePartialReassemble) { - std::fill(vertexColor_.begin(), - vertexColor_.end(), - Red); - std::fill(elementColor_.begin(), - elementColor_.end(), - Red); - std::fill(vertexDelta_.begin(), - vertexDelta_.end(), - 0.0); - } - } - - /*! - * \brief Returns the relative error below which a vertex is - * considered to be "green" if partial Jacobian reassembly - * is enabled. - * - * This returns the _actual_ relative computed seen by - * computeColors(), not the tolerance which it was given. - */ - Scalar reassembleTolerance() const - { return reassembleTolerance_; } - - /*! - * \brief Update the distance where the non-linear system was - * originally insistently linearized and the point where it - * will be linerized the next time. - * - * This only has an effect if partial reassemble is enabled. - */ - void updateDiscrepancy(const SolutionVector &u, - const SolutionVector &uDelta) - { - if (!enablePartialReassemble) - return; - - // update the vector with the distances of the current - // evaluation point used for linearization from the original - // evaluation point - for (int i = 0; i < vertexDelta_.size(); ++i) { - PrimaryVariables uCurrent(u[i]); - PrimaryVariables uNext(uCurrent); - uNext -= uDelta[i]; - - // we need to add the distance the solution was moved for - // this vertex - Scalar dist = model_().relativeErrorVertex(i, - uCurrent, - uNext); - vertexDelta_[i] += std::abs(dist); - } - - } - - /*! - * \brief Determine the colors of vertices and elements for partial - * reassembly given a relative tolerance. - * - * The following approach is used: - * - * - Set all vertices and elements to 'green' - * - Mark all vertices as 'red' which exhibit an relative error above - * the tolerance - * - Mark all elements which feature a 'red' vetex as 'red' - * - Mark all vertices which are not 'red' and are part of a - * 'red' element as 'yellow' - * - Mark all elements which are not 'red' and contain a - * 'yellow' vertex as 'yellow' - * - * \param relTol The relative error below which a vertex won't be - * reassembled. Note that this specifies the - * worst-case relative error between the last - * linearization point and the current solution and - * _not_ the delta vector of the Newton iteration! - */ - void computeColors(Scalar relTol) - { - if (!enablePartialReassemble) - return; - - // mark the red vertices and update the tolerance of the - // linearization which actually will get achieved - nextReassembleTolerance_ = 0; - for (int i = 0; i < vertexColor_.size(); ++i) { - vertexColor_[i] = Green; - if (vertexDelta_[i] > relTol) { - // mark vertex as red if discrepancy is larger than - // the relative tolerance - vertexColor_[i] = Red; - } - nextReassembleTolerance_ = - std::max(nextReassembleTolerance_, vertexDelta_[i]); - }; - - // Mark all red elements - for (const auto& element : Dune::elements(gridView_())) { - // find out whether the current element features a red - // vertex - bool isRed = false; - int numVertices = element.subEntities(dim); - for (int i=0; i < numVertices; ++i) { - int globalI = vertexMapper_().subIndex(element, i, dim); - if (vertexColor_[globalI] == Red) { - isRed = true; - break; - } - }; - - // if yes, the element color is also red, else it is not - // red, i.e. green for the mean time - int eIdxGlobal = elementMapper_().index(element); - if (isRed) - elementColor_[eIdxGlobal] = Red; - else - elementColor_[eIdxGlobal] = Green; - } - - // Mark yellow vertices (as orange for the mean time) - for (const auto& element : Dune::elements(gridView_())) { - int eIdx = this->elementMapper_().index(element); - if (elementColor_[eIdx] != Red) - continue; // non-red elements do not tint vertices - // yellow! - - int numVertices = element.subEntities(dim); - for (int i=0; i < numVertices; ++i) { - int globalI = vertexMapper_().subIndex(element, i, dim); - // if a vertex is already red, don't recolor it to - // yellow! - if (vertexColor_[globalI] != Red) - vertexColor_[globalI] = Orange; - }; - } - - // Mark yellow elements - for (const auto& element : Dune::elements(gridView_())) { - int eIdx = this->elementMapper_().index(element); - if (elementColor_[eIdx] == Red) { - continue; // element is red already! - } - - // check whether the element features a yellow - // (resp. orange at this point) vertex - bool isYellow = false; - int numVertices = element.subEntities(dim); - for (int i=0; i < numVertices; ++i) { - int globalI = vertexMapper_().subIndex(element, i, dim); - if (vertexColor_[globalI] == Orange) { - isYellow = true; - break; - } - }; - - if (isYellow) - elementColor_[eIdx] = Yellow; - } - - // Demote orange vertices to yellow ones if it has at least - // one green element as a neighbor. - for (const auto& element : Dune::elements(gridView_())) { - int eIdx = this->elementMapper_().index(element); - if (elementColor_[eIdx] != Green) - continue; // yellow and red elements do not make - // orange vertices yellow! - - int numVertices = element.subEntities(dim); - for (int i=0; i < numVertices; ++i) { - int globalI = vertexMapper_().subIndex(element, i, dim); - // if a vertex is orange, recolor it to yellow! - if (vertexColor_[globalI] == Orange) - vertexColor_[globalI] = Yellow; - }; - } - - // promote the remaining orange vertices to red - for (int i=0; i < vertexColor_.size(); ++i) { - // if a vertex is green or yellow don't do anything! - if (vertexColor_[i] == Green || vertexColor_[i] == Yellow) - continue; - - // make sure the vertex is red (this is a no-op vertices - // which are already red!) - vertexColor_[i] = Red; - - // set the error of this vertex to 0 because the system - // will be consistently linearized at this vertex - vertexDelta_[i] = 0.0; - }; - }; - - /*! - * \brief Returns the reassemble color of a vertex - * - * \param element An element which contains the vertex - * \param vIdx The local index of the vertex in the element. - */ - int vertexColor(const Element &element, int vIdx) const - { - if (!enablePartialReassemble) - return Red; // reassemble unconditionally! - - int vIdxGlobal = vertexMapper_().subIndex(element, vIdx, dim); - - return vertexColor_[vIdxGlobal]; - } - - /*! - * \brief Returns the reassemble color of a vertex - * - * \param vIdxGlobal The global index of the vertex. - */ - int vertexColor(int vIdxGlobal) const - { - if (!enablePartialReassemble) - return Red; // reassemble unconditionally! - return vertexColor_[vIdxGlobal]; - } - - /*! - * \brief Returns the Jacobian reassemble color of an element - * - * \param element The Codim-0 DUNE entity - */ - int elementColor(const Element &element) const - { - if (!enablePartialReassemble) - return Red; // reassemble unconditionally! - - int eIdxGlobal = elementMapper_().index(element); - return elementColor_[eIdxGlobal]; - } - - /*! - * \brief Returns the Jacobian reassemble color of an element - * - * \param globalElementIdx The global index of the element. - */ - int elementColor(int globalElementIdx) const - { - if (!enablePartialReassemble) - return Red; // reassemble unconditionally! - return elementColor_[globalElementIdx]; - } - - /*! - * \brief Returns a pointer to the PDELab's grid function space. - */ - const GridFunctionSpace& gridFunctionSpace() const - { - return *gridFunctionSpace_; - } - - /*! - * \brief Returns a pointer to the PDELab's constraints - * transformation. - */ - const ConstraintsTrafo& constraintsTrafo() const - { - return *constraintsTrafo_; - } - - /*! - * \brief Return constant reference to global Jacobian matrix. - */ - const JacobianMatrix& matrix() const - { return *matrix_; } - - /*! - * \brief Return reference to global Jacobian matrix. - */ - JacobianMatrix& matrix() - { return *matrix_; } - - /*! - * \brief Return constant reference to global residual vector. - */ - const SolutionVector& residual() const - { return *residual_; } - - - /*! - * \brief Return reference to global residual vector. - */ - SolutionVector& residual() - { return *residual_; } - - const GridOperator &gridOperator() const - { return *gridOperator_;} - -private: - // reset the global linear system of equations. if partial - // reassemble is enabled, this means that the jacobian matrix must - // only be erased partially! - void resetSystem_() - { - // always reset the right hand side. - *residual_ = 0.0; - - if (!enablePartialReassemble) { - // If partial reassembly of the jacobian is not enabled, - // we can just reset everything! - (*matrix_) = 0; - return; - } - - // reset all entries corrosponding to a red vertex - for (int rowIdx = 0; rowIdx < matrix_->N(); ++rowIdx) { - if (vertexColor_[rowIdx] == Green) - continue; // the equations for this control volume are - // already below the treshold - - // set all entries in the row to 0 - typedef typename JacobianMatrix::ColIterator ColIterator; - ColIterator colIt = (*matrix_)[rowIdx].begin(); - const ColIterator &colEndIt = (*matrix_)[rowIdx].end(); - for (; colIt != colEndIt; ++colIt) { - (*colIt) = 0.0; - } - }; - } - - Problem &problem_() - { return *problemPtr_; } - const Problem &problem_() const - { return *problemPtr_; } - const Model &model_() const - { return problem_().model(); } - Model &model_() - { return problem_().model(); } - const GridView &gridView_() const - { return problem_().gridView(); } - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); } - const ElementMapper &elementMapper_() const - { return problem_().elementMapper(); } - - Problem *problemPtr_; - - // the jacobian matrix - std::shared_ptr<JacobianMatrix> matrix_; - // the right-hand side - std::shared_ptr<SolutionVector> residual_; - - // attributes required for jacobian matrix recycling - bool reuseMatrix_; - - // attributes required for partial jacobian reassembly - std::vector<EntityColor> vertexColor_; - std::vector<EntityColor> elementColor_; - std::vector<Scalar> vertexDelta_; - - int totalElems_; - int greenElems_; - - Scalar nextReassembleTolerance_; - Scalar reassembleTolerance_; - - - std::shared_ptr<Constraints> constraints_; - std::shared_ptr<PressureFEM> pressureFEM_; - std::shared_ptr<DisplacementFEM> displacementFEM_; - std::shared_ptr<PressureScalarGFS> pressureScalarGFS_; - std::shared_ptr<DisplacementScalarGFS> displacementScalarGFS_; - std::shared_ptr<PressureGFS> pressureGFS_; - std::shared_ptr<DisplacementGFS> displacementGFS_; - std::shared_ptr<GridFunctionSpace> gridFunctionSpace_; - std::shared_ptr<ConstraintsTrafo> constraintsTrafo_; - std::shared_ptr<LocalOperator> localOperator_; - std::shared_ptr<GridOperator> gridOperator_; -}; - -} // namespace PDELab - -} // namespace Dumux +#include <dumux/geomechanics/el2p/assembler.hh> #endif diff --git a/dumux/geomechanics/el2p/el2pbasemodel.hh b/dumux/geomechanics/el2p/el2pbasemodel.hh index e79afb3c6ee5bd22e52e559663f4fdff999f8e35..83f6185f3f84320939284381a4bf0c60461af84c 100644 --- a/dumux/geomechanics/el2p/el2pbasemodel.hh +++ b/dumux/geomechanics/el2p/el2pbasemodel.hh @@ -1,984 +1,8 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * See the file COPYING for full copying permissions. * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -/*! - * \file - * \brief Base class for fully-implicit models - */ -#ifndef DUMUX_ELASTIC2P_BASE_MODEL_HH -#define DUMUX_ELASTIC2P_BASE_MODEL_HH +#ifndef DUMUX_ELASTIC2P_BASE_MODEL_HH_OLD +#define DUMUX_ELASTIC2P_BASE_MODEL_HH_OLD -#include <dune/geometry/type.hh> -#include <dune/istl/bvector.hh> +#warning this header is deprecated, use dumux/geomechanics/el2p/basemodel.hh instead -#include <dumux/implicit/model.hh> -#include <dumux/common/valgrind.hh> -#include <dumux/parallel/vertexhandles.hh> - -namespace Dumux -{ - -/*! - * \ingroup ElTwoPBoxModel - * \brief base class for the two-phase geomechanics model - */ -template<class TypeTag> -class ElTwoPBaseModel -{ - typedef typename GET_PROP_TYPE(TypeTag, Model) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) JacobianAssembler; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - - enum { - numEq = GET_PROP_VALUE(TypeTag, NumEq), - dim = GridView::dimension - }; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, LocalJacobian) LocalJacobian; - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual; - typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod; - typedef typename GET_PROP_TYPE(TypeTag, NewtonController) NewtonController; - - typedef typename GridView::ctype CoordScalar; - typedef typename GridView::template Codim<0>::Entity Element; - - typedef typename Dune::ReferenceElements<CoordScalar, dim> ReferenceElements; - typedef typename Dune::ReferenceElement<CoordScalar, dim> ReferenceElement; - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - - // copying a model is not a good idea - ElTwoPBaseModel(const ElTwoPBaseModel &); - -public: - /*! - * \brief The constructor. - */ - ElTwoPBaseModel() - : problemPtr_(0) - { - enableHints_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableHints); - } - - /*! - * \brief Apply the initial conditions to the model. - * - * \param problem The object representing the problem which needs to - * be simulated. - */ - void init(Problem &problem) - { - problemPtr_ = &problem; - - updateBoundaryIndices_(); - - int numDofs = asImp_().numDofs(); - if (isBox) - boxVolume_.resize(numDofs); - - localJacobian_.init(problem_()); - jacAsm_ = std::make_shared<JacobianAssembler>(); - jacAsm_->init(problem_()); - - uCur_ = std::make_shared<SolutionVector>(jacAsm_->gridFunctionSpace()); - uPrev_ = std::make_shared<SolutionVector>(jacAsm_->gridFunctionSpace()); - - asImp_().applyInitialSolution_(); - - // resize the hint vectors - if (isBox && enableHints_) { - int numVertices = gridView_().size(dim); - curHints_.resize(numVertices); - prevHints_.resize(numVertices); - hintsUsable_.resize(numVertices); - std::fill(hintsUsable_.begin(), - hintsUsable_.end(), - false); - } - - // also set the solution of the "previous" time step to the - // initial solution. - *uPrev_ = *uCur_; - } - - void setHints(const Element &element, - ElementVolumeVariables &prevVolVars, - ElementVolumeVariables &curVolVars) const - { - if (!isBox || !enableHints_) - return; - - int n = element.subEntities(dim); - prevVolVars.resize(n); - curVolVars.resize(n); - for (int i = 0; i < n; ++i) { - int vIdxGlobal = vertexMapper().subIndex(element, i, dim); - - if (!hintsUsable_[vIdxGlobal]) { - curVolVars[i].setHint(NULL); - prevVolVars[i].setHint(NULL); - } - else { - curVolVars[i].setHint(&curHints_[vIdxGlobal]); - prevVolVars[i].setHint(&prevHints_[vIdxGlobal]); - } - } - } - - void setHints(const Element &element, - ElementVolumeVariables &curVolVars) const - { - if (!isBox || !enableHints_) - return; - - int n = element.subEntities(dim); - curVolVars.resize(n); - for (int i = 0; i < n; ++i) { - int vIdxGlobal = vertexMapper().subIndex(element, i, dim); - - if (!hintsUsable_[vIdxGlobal]) - curVolVars[i].setHint(NULL); - else - curVolVars[i].setHint(&curHints_[vIdxGlobal]); - } - } - - void updatePrevHints() - { - if (!isBox || !enableHints_) - return; - - prevHints_ = curHints_; - } - - void updateCurHints(const Element &element, - const ElementVolumeVariables &elemVolVars) const - { - if (!isBox || !enableHints_) - return; - - for (unsigned int i = 0; i < elemVolVars.size(); ++i) { - int vIdxGlobal = vertexMapper().subIndex(element, i, dim); - curHints_[vIdxGlobal] = elemVolVars[i]; - if (!hintsUsable_[vIdxGlobal]) - prevHints_[vIdxGlobal] = elemVolVars[i]; - hintsUsable_[vIdxGlobal] = true; - } - } - - - /*! - * \brief Compute the global residual for an arbitrary solution - * vector. - * - * \param residual Stores the result - * \param u The solution for which the residual ought to be calculated - */ - Scalar globalResidual(SolutionVector &residual, - const SolutionVector &u) - { - jacAsm_->gridOperator().residual(u, residual); - - // calculate the square norm of the residual - Scalar result2 = residual.base().two_norm2(); - if (gridView_().comm().size() > 1) - result2 = gridView_().comm().sum(result2); - - // add up the residuals on the process borders - if (isBox && gridView_().comm().size() > 1) { - VertexHandleSum<PrimaryVariables, SolutionVector, VertexMapper> - sumHandle(residual, vertexMapper()); - gridView_().communicate(sumHandle, - Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - } - - return std::sqrt(result2); - } - - /*! - * \brief Compute the global residual for the current solution - * vector. - * - * \param residual Stores the result - */ - Scalar globalResidual(SolutionVector &residual) - { - return globalResidual(residual, curSol()); - } - - /*! - * \brief Compute the integral over the domain of the storage - * terms of all conservation quantities. - * - * \param storage Stores the result - */ - void globalStorage(PrimaryVariables &storage) - { - storage = 0; - - for (const auto& element : Dune::elements(gridView_())) - { - if(element.partitionType() == Dune::InteriorEntity) - { - localResidual().evalStorage(element); - - if (isBox) - { - for (int i = 0; i < element.subEntities(dim); ++i) - storage += localResidual().storageTerm()[i]; - } - else - { - storage += localResidual().storageTerm()[0]; - } - } - } - - if (gridView_().comm().size() > 1) - storage = gridView_().comm().sum(storage); - } - - /*! - * \brief Returns the volume \f$\mathrm{[m^3]}\f$ of a given control volume. - * - * \param vIdxGlobal The global index of the control volume's - * associated vertex - */ - Scalar boxVolume(const int vIdxGlobal) const - { - if (isBox) - { - return boxVolume_[vIdxGlobal][0]; - } - else - { - DUNE_THROW(Dune::InvalidStateException, - "requested box volume for cell-centered model"); - } - } - - /*! - * \brief Reference to the current solution as a block vector. - */ - const SolutionVector &curSol() const - { return *uCur_; } - - /*! - * \brief Reference to the current solution as a block vector. - */ - SolutionVector &curSol() - { return *uCur_; } - - /*! - * \brief Reference to the previous solution as a block vector. - */ - const SolutionVector &prevSol() const - { return *uPrev_; } - - /*! - * \brief Reference to the previous solution as a block vector. - */ - SolutionVector &prevSol() - { return *uPrev_; } - - /*! - * \brief Returns the operator assembler for the global jacobian of - * the problem. - */ - JacobianAssembler &jacobianAssembler() - { return *jacAsm_; } - - /*! - * \copydoc jacobianAssembler() - */ - const JacobianAssembler &jacobianAssembler() const - { return *jacAsm_; } - - /*! - * \brief Returns the local jacobian which calculates the local - * stiffness matrix for an arbitrary element. - * - * The local stiffness matrices of the element are used by - * the jacobian assembler to produce a global linerization of the - * problem. - */ - LocalJacobian &localJacobian() - { return localJacobian_; } - /*! - * \copydoc localJacobian() - */ - const LocalJacobian &localJacobian() const - { return localJacobian_; } - - /*! - * \brief Returns the local residual function. - */ - LocalResidual &localResidual() - { return localJacobian().localResidual(); } - /*! - * \copydoc localResidual() - */ - const LocalResidual &localResidual() const - { return localJacobian().localResidual(); } - - /*! - * \brief Returns the maximum relative shift between two vectors of - * primary variables. - * - * \param priVars1 The first vector of primary variables - * \param priVars2 The second vector of primary variables - */ - Scalar relativeShiftAtDof(const PrimaryVariables &priVars1, - const PrimaryVariables &priVars2) - { - Scalar result = 0.0; - for (int j = 0; j < numEq; ++j) { - Scalar eqErr = std::abs(priVars1[j] - priVars2[j]); - eqErr /= std::max<Scalar>(1.0, std::abs(priVars1[j] + priVars2[j])/2); - - result = std::max(result, eqErr); - } - return result; - } - - /*! - * \brief Try to progress the model to the next timestep. - * - * \param solver The non-linear solver - * \param controller The controller which specifies the behaviour - * of the non-linear solver - */ - bool update(NewtonMethod &solver, - NewtonController &controller) - { -#if HAVE_VALGRIND - for (size_t i = 0; i < curSol().base().size(); ++i) - Valgrind::CheckDefined(curSol().base()[i]); -#endif // HAVE_VALGRIND - - asImp_().updateBegin(); - - bool converged = solver.execute(controller); - if (converged) { - asImp_().updateSuccessful(); - } - else - asImp_().updateFailed(); - -#if HAVE_VALGRIND - for (size_t i = 0; i < curSol().base().size(); ++i) { - Valgrind::CheckDefined(curSol().base()[i]); - } -#endif // HAVE_VALGRIND - - return converged; - } - - /*! - * \brief Check the plausibility of the current solution - * - * This has to be done by the actual model, it knows - * best, what (ranges of) variables to check. - * This is primarily a hook - * which the actual model can overload. - */ - void checkPlausibility() const - { } - - /*! - * \brief Called by the update() method before it tries to - * apply the newton method. This is primarily a hook - * which the actual model can overload. - */ - void updateBegin() - { } - - - /*! - * \brief Called by the update() method if it was - * successful. This is primarily a hook which the actual - * model can overload. - */ - void updateSuccessful() - { } - - /*! - * \brief Called by the update() method if it was - * unsuccessful. This is primarily a hook which the actual - * model can overload. - */ - void updateFailed() - { - // Reset the current solution to the one of the - // previous time step so that we can start the next - // update at a physically meaningful solution. - *uCur_ = *uPrev_; - if (isBox) - curHints_ = prevHints_; - - jacAsm_->reassembleAll(); - } - - /*! - * \brief Called by the problem if a time integration was - * successful, post processing of the solution is done and - * the result has been written to disk. - * - * This should prepare the model for the next time integration. - */ - void advanceTimeLevel() - { - // make the current solution the previous one. - *uPrev_ = *uCur_; - if (isBox) - prevHints_ = curHints_; - - updatePrevHints(); - } - - /*! - * \brief Serializes the current state of the model. - * - * \tparam Restarter The type of the serializer class - * - * \param res The serializer object - */ - template <class Restarter> - void serialize(Restarter &res) - { - if (isBox) - res.template serializeEntities<dim>(asImp_(), gridView_()); - else - res.template serializeEntities<0>(asImp_(), gridView_()); - } - - /*! - * \brief Deserializes the state of the model. - * - * \tparam Restarter The type of the serializer class - * - * \param res The serializer object - */ - template <class Restarter> - void deserialize(Restarter &res) - { - if (isBox) - res.template deserializeEntities<dim>(asImp_(), gridView_()); - else - res.template deserializeEntities<0>(asImp_(), gridView_()); - - prevSol() = curSol(); - } - - /*! - * \brief Write the current solution for a vertex to a restart - * file. - * - * \param outstream The stream into which the vertex data should - * be serialized to - * \param entity The entity which's data should be - * serialized, i.e. a vertex for the box method - * and an element for the cell-centered method - */ - template <class Entity> - void serializeEntity(std::ostream &outstream, - const Entity &entity) - { - int dofIdxGlobal = dofMapper().index(entity); - - // write phase state - if (!outstream.good()) { - DUNE_THROW(Dune::IOError, - "Could not serialize vertex " - << dofIdxGlobal); - } - - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - outstream << curSol()[dofIdxGlobal][eqIdx] << " "; - } - } - - /*! - * \brief Reads the current solution variables for a vertex from a - * restart file. - * - * \param instream The stream from which the vertex data should - * be deserialized from - * \param entity The entity which's data should be - * serialized, i.e. a vertex for the box method - * and an element for the cell-centered method - */ - template <class Entity> - void deserializeEntity(std::istream &instream, - const Entity &entity) - { - int dofIdxGlobal = dofMapper().index(entity); - - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - if (!instream.good()) - DUNE_THROW(Dune::IOError, - "Could not deserialize vertex " - << dofIdxGlobal); - instream >> curSol()[dofIdxGlobal][eqIdx]; - } - } - - /*! - * \brief Returns the number of global degrees of freedoms (DOFs) - */ - size_t numDofs() const - { - if (isBox) - return gridView_().size(dim); - else - return gridView_().size(0); - } - - /*! - * \brief Mapper for the entities where degrees of freedoms are - * defined to indices. - * - * Is the box method is used, this means a mapper - * for vertices, if the cell centered method is used, - * this means a mapper for elements. - */ - template <class T = TypeTag> - const typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox), VertexMapper>::type &dofMapper() const - { - return problem_().vertexMapper(); - } - template <class T = TypeTag> - const typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox), ElementMapper>::type &dofMapper() const - { - return problem_().elementMapper(); - } - - /*! - * \brief Mapper for vertices to indices. - */ - const VertexMapper &vertexMapper() const - { return problem_().vertexMapper(); } - - /*! - * \brief Mapper for elements to indices. - */ - const ElementMapper &elementMapper() const - { return problem_().elementMapper(); } - - /*! - * \brief Resets the Jacobian matrix assembler, so that the - * boundary types can be altered. - */ - void resetJacobianAssembler () - { - jacAsm_.template reset<JacobianAssembler>(0); - jacAsm_ = std::make_shared<JacobianAssembler>(); - jacAsm_->init(problem_()); - } - - /*! - * \brief Update the weights of all primary variables within an - * element given the complete set of volume variables - * - * \param element The DUNE codim 0 entity - * \param volVars All volume variables for the element - */ - void updatePVWeights(const Element &element, - const ElementVolumeVariables &volVars) const - { } - - /*! - * \brief Add the vector fields for analysing the convergence of - * the newton method to the a VTK multi writer. - * - * \tparam MultiWriter The type of the VTK multi writer - * - * \param writer The VTK multi writer object on which the fields should be added. - * \param u The solution function - * \param deltaU The delta of the solution function before and after the Newton update - */ - template <class MultiWriter> - void addConvergenceVtkFields(MultiWriter &writer, - const SolutionVector &u, - const SolutionVector &deltaU) - { - typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; - - SolutionVector residual(u); - asImp_().globalResidual(residual, u); - - // create the required scalar fields - unsigned numDofs = asImp_().numDofs(); - - // global defect of the two auxiliary equations - ScalarField* def[numEq]; - ScalarField* delta[numEq]; - ScalarField* x[numEq]; - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - x[eqIdx] = writer.allocateManagedBuffer(numDofs); - delta[eqIdx] = writer.allocateManagedBuffer(numDofs); - def[eqIdx] = writer.allocateManagedBuffer(numDofs); - } - - for (unsigned int vIdxGlobal = 0; vIdxGlobal < u.base().size(); vIdxGlobal++) - { - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) - { - (*x[eqIdx])[vIdxGlobal] = u.base()[vIdxGlobal][eqIdx]; - (*delta[eqIdx])[vIdxGlobal] = - deltaU.base()[vIdxGlobal][eqIdx]; - (*def[eqIdx])[vIdxGlobal] = residual.base()[vIdxGlobal][eqIdx]; - } - } - - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - std::ostringstream oss; - oss.str(""); oss << "x_" << eqIdx; - if (isBox) - writer.attachVertexData(*x[eqIdx], oss.str()); - else - writer.attachCellData(*x[eqIdx], oss.str()); - oss.str(""); oss << "delta_" << eqIdx; - if (isBox) - writer.attachVertexData(*delta[eqIdx], oss.str()); - else - writer.attachCellData(*delta[eqIdx], oss.str()); - oss.str(""); oss << "defect_" << eqIdx; - if (isBox) - writer.attachVertexData(*def[eqIdx], oss.str()); - else - writer.attachCellData(*def[eqIdx], oss.str()); - } - - asImp_().addOutputVtkFields(u, writer); - } - - /*! - * \brief Add the quantities of a time step which ought to be written to disk. - * - * This should be overwritten by the actual model if any secondary - * variables should be written out. Read: This should _always_ be - * overwritten by well behaved models! - * - * \tparam MultiWriter The type of the VTK multi writer - * - * \param sol The global vector of primary variable values. - * \param writer The VTK multi writer where the fields should be added. - */ - template <class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, - MultiWriter &writer) - { - typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; - - // create the required scalar fields - unsigned numDofs = asImp_().numDofs(); - - // global defect of the two auxiliary equations - ScalarField* x[numEq]; - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - x[eqIdx] = writer.allocateManagedBuffer(numDofs); - } - - for (int vIdxGlobal = 0; vIdxGlobal < sol.size(); vIdxGlobal++) - { - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - (*x[eqIdx])[vIdxGlobal] = sol[vIdxGlobal][eqIdx]; - } - } - - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - std::ostringstream oss; - oss << "primaryVar_" << eqIdx; - if (isBox) - writer.attachVertexData(*x[eqIdx], oss.str()); - else - writer.attachCellData(*x[eqIdx], oss.str()); - } - } - - /*! - * \brief Reference to the grid view of the spatial domain. - */ - const GridView &gridView() const - { return problem_().gridView(); } - - /*! - * \brief Returns true if the entity indicated by 'dofIdxGlobal' - * is located on / touches the grid's boundary. - * - * \param dofIdxGlobal The global index of the entity - */ - bool onBoundary(const int dofIdxGlobal) const - { return boundaryIndices_[dofIdxGlobal]; } - - /*! - * \brief Returns true if a vertex is located on the grid's - * boundary. - * - * \param element A DUNE Codim<0> entity which contains the control - * volume's associated vertex. - * \param vIdx The local vertex index inside element - */ - bool onBoundary(const Element &element, const int vIdx) const - { - if (isBox) - return onBoundary(vertexMapper().subIndex(element, vIdx, dim)); - else - DUNE_THROW(Dune::InvalidStateException, - "requested for cell-centered model"); - } - - - /*! - * \brief Returns true if the control volume touches - * the grid's boundary. - * - * \param element A DUNE Codim<0> entity coinciding with the control - * volume. - */ - bool onBoundary(const Element &element) const - { - if (!isBox) - return onBoundary(elementMapper().index(element)); - else - DUNE_THROW(Dune::InvalidStateException, - "requested for box model"); - } - - /*! - * \brief Fill the fluid state according to the primary variables. - * - * Taking the information from the primary variables, - * the fluid state is filled with every information that is - * necessary to evaluate the model's local residual. - * - * \param priVars The primary variables of the model. - * \param problem The problem at hand. - * \param element The current element. - * \param fvGeometry The finite volume element geometry. - * \param scvIdx The index of the subcontrol volume. - * \param fluidState The fluid state to fill. - */ - template <class FluidState> - static void completeFluidState(const PrimaryVariables& priVars, - const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const int scvIdx, - FluidState& fluidState) - { - VolumeVariables::completeFluidState(priVars, problem, element, - fvGeometry, scvIdx, fluidState); - } -protected: - /*! - * \brief A reference to the problem on which the model is applied. - */ - Problem &problem_() - { return *problemPtr_; } - /*! - * \copydoc problem_() - */ - const Problem &problem_() const - { return *problemPtr_; } - - /*! - * \brief Reference to the grid view of the spatial domain. - */ - const GridView &gridView_() const - { return problem_().gridView(); } - - /*! - * \brief Reference to the local residal object - */ - LocalResidual &localResidual_() - { return localJacobian_.localResidual(); } - - /*! - * \brief Applies the initial solution for all vertices of the grid. - */ - void applyInitialSolution_() - { - // first set the whole domain to zero - *uCur_ = Scalar(0.0); - boxVolume_ = Scalar(0.0); - - FVElementGeometry fvGeometry; - - // iterate through leaf grid and evaluate initial - // condition at the center of each sub control volume - // - // TODO: the initial condition needs to be unique for - // each vertex. we should think about the API... - for (const auto& element : Dune::elements(gridView_())) { - // deal with the current element - fvGeometry.update(gridView_(), element); - - // loop over all element vertices, i.e. sub control volumes - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; scvIdx++) - { - // get the global index of the degree of freedom - int dofIdxGlobal = dofMapper().subIndex(element, scvIdx, dofCodim); - - // let the problem do the dirty work of nailing down - // the initial solution. - PrimaryVariables initPriVars; - Valgrind::SetUndefined(initPriVars); - problem_().initial(initPriVars, - element, - fvGeometry, - scvIdx); - Valgrind::CheckDefined(initPriVars); - - if (isBox) - { - // add up the initial values of all sub-control - // volumes. If the initial values disagree for - // different sub control volumes, the initial value - // will be the arithmetic mean. - initPriVars *= fvGeometry.subContVol[scvIdx].volume; - boxVolume_[dofIdxGlobal] += fvGeometry.subContVol[scvIdx].volume; - } - - uCur_->base()[dofIdxGlobal] += initPriVars; - Valgrind::CheckDefined(uCur_->base()[dofIdxGlobal]); - } - } - - // add up the primary variables and the volumes of the boxes - // which cross process borders - if (isBox && gridView_().comm().size() > 1) { - VertexHandleSum<Dune::FieldVector<Scalar, 1>, - Dune::BlockVector<Dune::FieldVector<Scalar, 1> >, - VertexMapper> sumVolumeHandle(boxVolume_, vertexMapper()); - gridView_().communicate(sumVolumeHandle, - Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - - VertexHandleSum<PrimaryVariables, SolutionVector, VertexMapper> - sumPVHandle(uCur_->base(), vertexMapper()); - gridView_().communicate(sumPVHandle, - Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - } - - if (isBox) - { - // divide all primary variables by the volume of their boxes - for (unsigned int i = 0; i < uCur_->base().size(); ++i) { - uCur_->base()[i] /= boxVolume(i); - } - } - } - - /*! - * \brief Find all indices of boundary vertices (box) / elements (cell centered). - */ - void updateBoundaryIndices_() - { - boundaryIndices_.resize(numDofs()); - std::fill(boundaryIndices_.begin(), boundaryIndices_.end(), false); - - for (const auto& element : Dune::elements(gridView_())) { - Dune::GeometryType geomType = element.geometry().type(); - const ReferenceElement &refElement = ReferenceElements::general(geomType); - - for (const auto& intersection : Dune::intersections(gridView_(), element)) { - if (intersection.boundary()) { - if (isBox) - { - // add all vertices on the intersection to the set of - // boundary vertices - int fIdx = intersection.indexInInside(); - int numFaceVerts = refElement.size(fIdx, 1, dim); - for (int faceVertexIdx = 0; - faceVertexIdx < numFaceVerts; - ++faceVertexIdx) - { - int vIdx = refElement.subEntity(fIdx, - 1, - faceVertexIdx, - dim); - int vIdxGlobal = vertexMapper().subIndex(element, vIdx, dim); - boundaryIndices_[vIdxGlobal] = true; - } - } - else - { - int eIdxGlobal = elementMapper().index(element); - boundaryIndices_[eIdxGlobal] = true; - } - } - } - } - } - - // the hint cache for the previous and the current volume - // variables - mutable std::vector<bool> hintsUsable_; - mutable std::vector<VolumeVariables> curHints_; - mutable std::vector<VolumeVariables> prevHints_; - - // the problem we want to solve. defines the constitutive - // relations, matxerial laws, etc. - Problem *problemPtr_; - - // calculates the local jacobian matrix for a given element - LocalJacobian localJacobian_; - // Linearizes the problem at the current time step using the - // local jacobian - std::shared_ptr<JacobianAssembler> jacAsm_; - - // the set of all indices of vertices on the boundary - std::vector<bool> boundaryIndices_; - - // cur is the current iterative solution, prev the converged - // solution of the previous time step - std::shared_ptr<SolutionVector> uCur_; - std::shared_ptr<SolutionVector> uPrev_; - - Dune::BlockVector<Dune::FieldVector<Scalar, 1> > boxVolume_; - -private: - /*! - * \brief Returns whether messages should be printed - */ - bool verbose_() const - { return gridView_().comm().rank() == 0; } - - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } - - bool enableHints_; -}; -} // end namespace Dumux +#include <dumux/geomechanics/el2p/basemodel.hh> #endif diff --git a/dumux/geomechanics/el2p/el2pelementvolumevariables.hh b/dumux/geomechanics/el2p/el2pelementvolumevariables.hh index b7d77be404494fdfeeac428711276fee61bfefed..34a95941be2daf10d9e5991394e0b2b6152a7a7e 100644 --- a/dumux/geomechanics/el2p/el2pelementvolumevariables.hh +++ b/dumux/geomechanics/el2p/el2pelementvolumevariables.hh @@ -1,303 +1,8 @@ -// -*- 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 Volume variables gathered on an element - */ -#ifndef DUMUX_BOX_EL2P_ELEMENT_VOLUME_VARIABLES_HH -#define DUMUX_BOX_EL2P_ELEMENT_VOLUME_VARIABLES_HH +#ifndef DUMUX_BOX_EL2P_ELEMENT_VOLUME_VARIABLES_HH_OLD +#define DUMUX_BOX_EL2P_ELEMENT_VOLUME_VARIABLES_HH_OLD -#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> +#warning this header is deprecated, use dumux/geomechanics/el2p/elementvolumevariables.hh instead -#include <dumux/implicit/box/elementvolumevariables.hh> -#include "el2pproperties.hh" - -namespace Dumux -{ - -/*! - * \ingroup ElTwoPBoxModel - * - * \brief This class stores an array of VolumeVariables objects, one - * volume variables object for each of the element's vertices - */ -template<class TypeTag> -class ElTwoPElementVolumeVariables : public std::vector<typename GET_PROP_TYPE(TypeTag, VolumeVariables) > -{ - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename Element::Geometry::JacobianInverseTransposed JacobianInverseTransposed; - - enum { dim = GridView::dimension }; - enum { dimWorld = GridView::dimensionworld }; - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; - - typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; - - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - pressureIdx = Indices::pressureIdx, - saturationIdx = Indices::saturationIdx - }; - -public: - /*! - * \brief The constructor. - */ - ElTwoPElementVolumeVariables() - { } - - /*! - * \brief Construct the volume variables for all vertices of an element. - * - * \param problem The problem which needs to be simulated. - * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated - * \param fvGeometry The finite volume geometry of the element - * \param isOldSol Tells whether the model's previous or current solution should be used. - * - * This class is required for the update of the effective porosity values at the - * vertices since it is a function of the divergence of the solid displacement - * at the integration points - */ - void update(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - bool isOldSol) - { - // retrieve the current or the previous solution vector and write the values into globalSol - const SolutionVector &globalSol = - isOldSol? - problem.model().prevSol(): - problem.model().curSol(); - - const GridFunctionSpace& gridFunctionSpace = problem.model().jacobianAssembler().gridFunctionSpace(); - const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); - // copy the values of the globalSol vector to the localFunctionSpace values of the current element - LocalFunctionSpace localFunctionSpace(gridFunctionSpace); - localFunctionSpace.bind(element); - std::vector<Scalar> values(localFunctionSpace.size()); - for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) - { - const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); - typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; - ordering.mapIndex(di.view(),ci); - values[k] = globalSol[ci]; - } - - // pressure and saturation local function space (mass balance equations) - typedef typename LocalFunctionSpace::template Child<0>::Type PressSatLFS; - const PressSatLFS& pressSatLFS = localFunctionSpace.template child<0>(); - // local function space for pressure - typedef typename PressSatLFS::template Child<0>::Type PressLFS; - const PressLFS& pressLFS = pressSatLFS.template child<0>(); - // local function space for saturation - typedef typename PressSatLFS::template Child<1>::Type SatLFS; - const SatLFS& satLFS = pressSatLFS.template child<1>(); - // local function space for solid displacement - typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; - const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); - typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; - - int numScv = element.subEntities(dim); - this->resize(numScv); - - for (int scvIdx = 0; scvIdx < numScv; scvIdx++) - { - // solution vector solI for each vertex - PrimaryVariables solI; - // pressure and saturation values - solI[pressureIdx] = values[pressLFS.localIndex(scvIdx)]; - solI[saturationIdx] = values[satLFS.localIndex(scvIdx)]; - // solid displacement values for each coordinate direction - for (int coordDir = 0; coordDir < dim; coordDir++) - { - const ScalarDispLFS& scalarDispLFS = displacementLFS.child(coordDir); - solI[Indices::u(coordDir)] = values[scalarDispLFS.localIndex(scvIdx)]; - } - // reset evaluation point to zero - (*this)[scvIdx].setEvalPoint(0); - - (*this)[scvIdx].update(solI, - problem, - element, - fvGeometry, - scvIdx, - isOldSol); - - Valgrind::CheckDefined((*this)[scvIdx]); - } - this->updateEffPorosity(problem, element, fvGeometry, isOldSol); - - if (isOldSol) - prevValues_ = values; - else - dofValues_ = values; - } - - /*! - * \brief Update the effective porosities for all vertices of an element. - * - * \param problem The problem which needs to be simulated. - * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated - * \param fvGeometry The finite volume geometry of the element - * \param isOldSol Specifies whether this is the previous solution or the current one - * - * This function is required for the update of the effective porosity values at the - * vertices. - * - * During the partial derivative calculation, changes of the solid displacement - * at vertex i can affect effective porosities of all element vertices. - * To correctly update the effective porosities of all element vertices - * an iteration over all scv faces is required. - * The remaining volvars are only updated for the vertex whose primary variable - * is changed for the derivative calculation. - */ - void updateEffPorosity(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - bool isOldSol) - { - int numScv = element.subEntities(dim); - - // retrieve the current or the previous solution vector and write the values into globalSol - const SolutionVector &globalSol = - isOldSol? - problem.model().prevSol(): - problem.model().curSol(); - - // copy the values of the globalSol vector to the localFunctionSpace values of the current element - const GridFunctionSpace& gridFunctionSpace = problem.model().jacobianAssembler().gridFunctionSpace(); - const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); - LocalFunctionSpace localFunctionSpace(gridFunctionSpace); - localFunctionSpace.bind(element); - std::vector<Scalar> values(localFunctionSpace.size()); - for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) - { - const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); - typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; - ordering.mapIndex(di.view(),ci); - values[k] = globalSol[ci]; - } - - // local function space for solid displacement - typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; - const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); - const unsigned int dispSize = displacementLFS.child(0).size(); - typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; - // further types required for gradient calculations - typedef typename ScalarDispLFS::Traits::FiniteElementType:: - Traits::LocalBasisType::Traits::JacobianType JacobianType_V; - typedef typename ScalarDispLFS::Traits::FiniteElementType:: - Traits::LocalBasisType::Traits::RangeFieldType RF; - typedef Dune::FieldMatrix<RF, dim, dim> Tensor; - - for (int scvIdx = 0; scvIdx < numScv; scvIdx++) - (*this)[scvIdx].effPorosity = 0.0; - - for (int scvIdx = 0; scvIdx < numScv; scvIdx++) - { - GlobalPosition scvCenter = fvGeometry.subContVol[scvIdx].localCenter; - - // evaluate gradient of displacement shape functions at the center of - // the sub control volume in the reference element - std::vector<JacobianType_V> vRefShapeGradient(dispSize); - displacementLFS.child(0).finiteElement().localBasis().evaluateJacobian(scvCenter, vRefShapeGradient); - - // transform gradient to element in global coordinates - const JacobianInverseTransposed jacInvT = element.geometry().jacobianInverseTransposed(scvCenter); - std::vector<Dune::FieldVector<RF,dim> > vShapeGradient(dispSize); - - // loop over element vertices - for (size_t i = 0; i < dispSize; i++) - { - vShapeGradient[i] = 0.0; - jacInvT.umv(vRefShapeGradient[i][0],vShapeGradient[i]); - } - - // calculate gradient of current displacement - // (gradient of a vector is a tensor) - Tensor uGradient(0.0); - // loop over coordinate directions - for(int coordDir = 0; coordDir < dim; ++coordDir) - { - const ScalarDispLFS & scalarDispLFS = displacementLFS.child(coordDir); - // loop over element vertices - for (size_t i = 0; i < scalarDispLFS.size(); i++) - uGradient[coordDir].axpy((*this)[i].displacement(coordDir), vShapeGradient[i]); - } - - // calculate the divergence of u - (*this)[scvIdx].divU = 0.0; - - for (int coordDir = 0; coordDir < dim; coordDir++) - (*this)[scvIdx].divU += uGradient[coordDir][coordDir]; - - // calculate the effective porosity - if(problem.coupled() == true) - { - if ((*this)[scvIdx].divU < -(*this)[scvIdx].porosity()) - { - (*this)[scvIdx].effPorosity = (*this)[scvIdx].porosity(); - std::cout<<"volume change too large"<<std::endl; - } - else - // this equation would be correct if the bulk volume could change (Vol_new = Vol_init *(1+div u)), however, we - // have a constant bulk volume therefore we should apply phi_eff = phi_init + div u - // but this causes convergence problems. Since div u is very small here the chosen relation is - // assumed to be a good approximation - (*this)[scvIdx].effPorosity = ((*this)[scvIdx].porosity() + (*this)[scvIdx].divU)/(1.0 + (*this)[scvIdx].divU); - } - else - (*this)[scvIdx].effPorosity = (*this)[scvIdx].porosity(); - } - } - - - const std::vector<Scalar>& dofValues() const - { - return dofValues_; - } - - Scalar& dofValues(int k) - { - return dofValues_[k]; - } - - const std::vector<Scalar>& prevValues() const - { - return prevValues_; - } - -private: - std::vector<Scalar> dofValues_; - std::vector<Scalar> prevValues_; -}; - -} // namespace Dumux +#include <dumux/geomechanics/el2p/elementvolumevariables.hh> #endif diff --git a/dumux/geomechanics/el2p/el2pfluxvariables.hh b/dumux/geomechanics/el2p/el2pfluxvariables.hh index db36516d5903e36f81f21a0285ab0ffc67099541..75eae8897ae5b0b00a45788e8336fce667f3552d 100644 --- a/dumux/geomechanics/el2p/el2pfluxvariables.hh +++ b/dumux/geomechanics/el2p/el2pfluxvariables.hh @@ -1,270 +1,8 @@ -// -*- 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 This file contains the calculation of all the fluxes over the surface of the - * finite volume that make up the volume, the mass and the momentum balance - * for the two-phase linear-elastic model. - * - * This means pressure, concentration and solid-displacement gradients, phase densities at - * the integration point, etc. - * - * This class inherits from the two-phase model FluxVariables - */ -#ifndef DUMUX_EL2P_FLUX_VARIABLES_HH -#define DUMUX_EL2P_FLUX_VARIABLES_HH +#ifndef DUMUX_EL2P_FLUX_VARIABLES_HH_OLD +#define DUMUX_EL2P_FLUX_VARIABLES_HH_OLD -#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> -#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> -#include "el2pproperties.hh" +#warning this header is deprecated, use dumux/geomechanics/el2p/fluxvariables.hh instead -namespace Dumux -{ - -namespace Properties -{ -// forward declaration of properties -NEW_PROP_TAG(SpatialParams); -} -/*! - * \ingroup ElTwoPBoxModel - * \ingroup ImplicitFluxVariables - * \brief This template class contains the data which is required to - * calculate the fluxes over the surface of the - * finite volume that make up the volume, the mass and the momentum balance - * for the two-phase linear-elastic model. - * - * This means pressure, concentration and solid-displacement gradients, phase densities at - * the integration point, etc. - * - */ - template<class TypeTag> - class ElTwoPFluxVariables: public ImplicitDarcyFluxVariables<TypeTag> - { - typedef ImplicitDarcyFluxVariables<TypeTag> TwoPBase; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - enum - { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld - }; - - typedef typename GridView::ctype CoordScalar; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - typedef Dune::FieldVector<CoordScalar, dim> DimVector; - typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimMatrix; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; - - enum {numEq = GET_PROP_VALUE(TypeTag, NumEq)}; - - public: - /* - * \brief The constructor - * - * \param problem The problem - * \param element The finite element - * \param fvGeometry The finite-volume geometry in the fully implicit scheme - * \param fIdx The local index of the SCV (sub-control-volume) face - * \param elemVolVars The volume variables of the current element - * \param onBoundary A boolean variable to specify whether the flux variables - * are calculated for interior SCV faces or boundary faces, default=false - */ - ElTwoPFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : TwoPBase(problem, element, fvGeometry, fIdx, elemVolVars), - fvGeometry_(fvGeometry), faceIdx_(fIdx) - { - dU_ = Scalar(0); - timeDerivUNormal_ = Scalar(0); - - elTwoPGradients_(problem, element, elemVolVars); - calculateDDt_(problem, element, elemVolVars); - calculateK_(problem, element, elemVolVars); - } - ; - - public: - /*! - * \brief Return change of u [m] with time at integration point - * point. - */ - Scalar dU(int dimIdx) const - { - return dU_[dimIdx]; - } - - /*! - * \brief Return time derivative of u [m/s] in normal - * direction at integration point - */ - Scalar timeDerivUNormal() const - { - return timeDerivUNormal_; - } - - /* - * \brief Return the intrinsic permeability. - */ - const DimMatrix &intrinsicPermeability() const - { - return K_; - } - - /* - * \brief Return the gradient of the potential for each phase. - */ - DimVector potentialGrad(int phaseIdx) const - { - return this->potentialGrad_[phaseIdx]; - } - - const SCVFace &face() const - { - return fvGeometry_.subContVolFace[faceIdx_]; - } - - protected: - /*! - * \brief Calculation of the solid displacement gradients. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void elTwoPGradients_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; - typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; - const GridFunctionSpace& gridFunctionSpace = problem.model().jacobianAssembler().gridFunctionSpace(); - const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); - LocalFunctionSpace localFunctionSpace(gridFunctionSpace); - localFunctionSpace.bind(element); - // copy values of previous solution into prevSolutionValues Vector - std::vector<Scalar> prevSolutionValues(localFunctionSpace.size()); - // copy values of current solution into curSolutionValues Vector - std::vector<Scalar> curSolutionValues(localFunctionSpace.size()); - for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) - { - const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); - typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; - ordering.mapIndex(di.view(),ci); - prevSolutionValues[k] = problem.model().prevSol()[ci]; - curSolutionValues[k] = problem.model().curSol()[ci]; - } - - // type of function space for solid displacement vector - typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; - const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); - // number of degrees of freedom for each displacement value (here number of element vertices) - const unsigned int dispSize = displacementLFS.child(0).size(); - // type of function space of solid displacement value (one for each coordinate direction) - typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; - typedef typename ScalarDispLFS::Traits::FiniteElementType::Traits::LocalBasisType::Traits::RangeType RT_V; - - for(int coordDir = 0; coordDir < dim; ++coordDir) { - // get displacement function space for coordinate direction coordDir - const ScalarDispLFS & scalarDispLFS = displacementLFS.child(coordDir); - std::vector<RT_V> vShape(dispSize); - // evaluate shape functions of all element vertices for current integration point and write it into vector vShape - scalarDispLFS.finiteElement().localBasis().evaluateFunction(face().ipLocal, vShape); - - dU_[coordDir] = 0; - // subtract previous displacement value from current displacement value for each coordinate direction - // coordDir and for each node i and interpolate values at integration point via the shape function vShape. - // TODO: evaluation of prevVolVars should also be possible--> check - for (size_t i = 0; i < dispSize; i++){ - dU_[coordDir] += (elemVolVars[i].primaryVars()[(numEq - dim)+coordDir] - - prevSolutionValues[scalarDispLFS.localIndex(i)])*vShape[i]; - } - } - } - - /*! - * \brief Calculation of the time derivative of solid displacement - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateDDt_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - Scalar dt = problem.timeManager().timeStepSize(); - - DimVector tmp(0.0); - // calculate time derivative of solid displacement vector - for (int coordDir = 0; coordDir < dim; ++coordDir) - tmp[coordDir] = dU(coordDir) / dt; - - // multiply time derivative of solid displacement vector with - // normal vector of current scv-face - timeDerivUNormal_ = tmp * face().normal; - } - - /*! - * \brief Calculation the harmonic mean of the intrinsic permeability tensor - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateK_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - // calculate the mean intrinsic permeability - const SpatialParams &spatialParams = problem.spatialParams(); - spatialParams.meanK(K_, - spatialParams.intrinsicPermeability(element, - fvGeometry_, - face().i), - spatialParams.intrinsicPermeability(element, - fvGeometry_, - face().j)); - } - - const FVElementGeometry &fvGeometry_; - int faceIdx_; - - //! time derivative of solid displacement times normal vector at integration point - Scalar timeDerivUNormal_; - //! change of solid displacement with time at integration point - GlobalPosition dU_; - // intrinsic permeability - DimMatrix K_; - }; - -} // end namespace +#include <dumux/geomechanics/el2p/fluxvariables.hh> #endif diff --git a/dumux/geomechanics/el2p/el2pindices.hh b/dumux/geomechanics/el2p/el2pindices.hh index 0ee0d1d5045aa681b0b1787172ffedd86040312d..0c824cdda8fc97f4ee94cfaffddccda34557bab8 100644 --- a/dumux/geomechanics/el2p/el2pindices.hh +++ b/dumux/geomechanics/el2p/el2pindices.hh @@ -1,58 +1,8 @@ -// -*- 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 Defines the primary variable and equation indices used by - * the two-phase linear elasticity model. - */ -#ifndef DUMUX_ELASTIC2P_INDICES_HH -#define DUMUX_ELASTIC2P_INDICES_HH +#ifndef DUMUX_ELASTIC2P_INDICES_HH_OLD +#define DUMUX_ELASTIC2P_INDICES_HH_OLD -#include <dumux/geomechanics/elastic/elasticindices.hh> -#include <dumux/porousmediumflow/2p/implicit/indices.hh> +#warning this header is deprecated, use dumux/geomechanics/el2p/indices.hh instead -namespace Dumux -{ -// \{ - -namespace Properties -{ - -/*! - * \ingroup ElTwoPBoxModel - * \ingroup ImplicitIndices - * \brief The indices for the two-phase linear elasticity model. - * - * This class inherits from the TwoPIndices and from the ElasticIndices - */ - -// PVOffset is set to 0 for the TwoPIndices and to 2 for the ElasticIndices since -// the first two primary variables are the primary variables of the two-phase -// model followed by the primary variables of the elastic model -template <class TypeTag, -int formulation = 0, -int PVOffset = 2> -class ElTwoPIndices : public ElasticIndices<PVOffset>, public TwoPIndices<TypeTag,0> -{}; - -} -} +#include <dumux/geomechanics/el2p/indices.hh> #endif diff --git a/dumux/geomechanics/el2p/el2plocaljacobian.hh b/dumux/geomechanics/el2p/el2plocaljacobian.hh index 348bc8da58d8c821b5409b3ec5d64e4d8eeca075..916c6704b6e1cf4c427aeb5693f5f77ecd8d96c0 100644 --- a/dumux/geomechanics/el2p/el2plocaljacobian.hh +++ b/dumux/geomechanics/el2p/el2plocaljacobian.hh @@ -1,257 +1,8 @@ -// -*- 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 Calculates the partial derivatives of the local residual for the Jacobian of the - * two-phase linear elasticity model. - */ -#ifndef DUMUX_EL2P_LOCAL_JACOBIAN_HH -#define DUMUX_EL2P_LOCAL_JACOBIAN_HH +#ifndef DUMUX_EL2P_LOCAL_JACOBIAN_HH_OLD +#define DUMUX_EL2P_LOCAL_JACOBIAN_HH_OLD -#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> -#include <dumux/implicit/localjacobian.hh> -#include "el2pproperties.hh" +#warning this header is deprecated, use dumux/geomechanics/el2p/localjacobian.hh instead -namespace Dumux -{ -/*! - * \ingroup ElTwoPBoxModel - * \brief Calculates the partial derivatives of the local residual for the Jacobian - * - * Except for the evalPartialDerivatives function all functions are taken from the - * base class ImplicitLocalJacobian - */ -template<class TypeTag> -class ElTwoPLocalJacobian : public ImplicitLocalJacobian<TypeTag> -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum { - dim = GridView::dimension, - }; - 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, Scalar) Scalar; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - pressureIdx = Indices::pressureIdx, - saturationIdx = Indices::saturationIdx - }; - // copying a local jacobian is not a good idea - ElTwoPLocalJacobian(const ElTwoPLocalJacobian &); - -public: - ElTwoPLocalJacobian() {} - - /*! - * \brief Compute the partial derivatives to a primary variable at - * an degree of freedom. - * - * This method is overwritten here since this model requires a call of the model specific - * elementvolumevariables which updates the effective porosities correctly. - * - * 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 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, - int col, - int pvIdx) - { - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; - typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; - - // copy the values of the globalSol vector to the localFunctionSpace values of the current element - const GridFunctionSpace& gridFunctionSpace = this->problemPtr_->model().jacobianAssembler().gridFunctionSpace(); - const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); - LocalFunctionSpace localFunctionSpace(gridFunctionSpace); - localFunctionSpace.bind(this->element_()); - std::vector<Scalar> elementValues(localFunctionSpace.size()); - for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) - { - const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); - typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; - ordering.mapIndex(di.view(),ci); - elementValues[k] = this->problemPtr_->model().curSol()[ci]; - } - // pressure and saturation local function space (mass balance equations) - typedef typename LocalFunctionSpace::template Child<0>::Type PressSatLFS; - const PressSatLFS& pressSatLFS = localFunctionSpace.template child<0>(); - // local function space for pressure - typedef typename PressSatLFS::template Child<0>::Type PressLFS; - const PressLFS& pressLFS = pressSatLFS.template child<0>(); - // local function space for saturation - typedef typename PressSatLFS::template Child<1>::Type SatLFS; - const SatLFS& satLFS = pressSatLFS.template child<1>(); - // local function space for solid displacement - typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; - const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); - typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; - - //primary variable vector priVars for each vertex - PrimaryVariables priVars; - priVars[pressureIdx] = elementValues[pressLFS.localIndex(col)]; - priVars[saturationIdx] = elementValues[satLFS.localIndex(col)]; - for (int coordDir = 0; coordDir < dim; coordDir++) - { - const ScalarDispLFS& scalarDispLFS = displacementLFS.child(coordDir); - priVars[Indices::u(coordDir)] = elementValues[scalarDispLFS.localIndex(col)]; - } - - VolumeVariables origVolVars(this->curVolVars_[col]); - this->curVolVars_[col].setEvalPoint(&origVolVars); - Scalar eps = this->numericEpsilon(col, pvIdx); - Scalar delta = 0; - - if (this->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 - this->curVolVars_[col].update(priVars, - this->problem_(), - this->element_(), - this->fvElemGeom_, - col, - false); - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_, - false); - - this->localResidual().eval(this->element_(), - this->fvElemGeom_, - this->prevVolVars_, - this->curVolVars_, - this->bcTypes_); - - // store the residual - partialDeriv = this->localResidual().residual(); - storageDeriv = this->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 = this->residual_; - storageDeriv = this->storageTerm_[col]; - } - - - if (this->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 - this->curVolVars_[col].update(priVars, - this->problem_(), - this->element_(), - this->fvElemGeom_, - col, - false); - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_, - false); - this->localResidual().eval(this->element_(), - this->fvElemGeom_, - this->prevVolVars_, - this->curVolVars_, - this->bcTypes_); - partialDeriv -= this->localResidual().residual(); - storageDeriv -= this->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 -= this->residual_; - storageDeriv -= this->storageTerm_[col]; - } - - // divide difference in residuals by the magnitude of the - // deflections between the two function evaluation -// if(partialDeriv[col][pvIdx] == -350045) - - partialDeriv /= delta; - storageDeriv /= delta; - // restore the orignal state of the element's volume variables - this->curVolVars_[col] = origVolVars; - // update the effective porosities - this->curVolVars_.updateEffPorosity(this->problem_(), - this->element_(), - this->fvElemGeom_, - false); - -#if HAVE_VALGRIND - for (unsigned i = 0; i < partialDeriv.size(); ++i) - Valgrind::CheckDefined(partialDeriv[i]); -#endif - } -}; -} +#include <dumux/geomechanics/el2p/localjacobian.hh> #endif diff --git a/dumux/geomechanics/el2p/el2plocaloperator.hh b/dumux/geomechanics/el2p/el2plocaloperator.hh index 5c2c3cc565d1fc4019801f73a9eb45d5da676686..4ec5a64715961432df0d96777890f185bb11cc17 100644 --- a/dumux/geomechanics/el2p/el2plocaloperator.hh +++ b/dumux/geomechanics/el2p/el2plocaloperator.hh @@ -1,635 +1,8 @@ -// -*- 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 This file contains a local operator for PDELab which - * wraps the contributions from - * el2plocalresidual (box discretized mass balances) - * and alphaMomentum (FE discretized momentum balance). - */ -#ifndef DUMUX_EL2P_LOCAL_OPERATOR_HH -#define DUMUX_EL2P_LOCAL_OPERATOR_HH +#ifndef DUMUX_EL2P_LOCAL_OPERATOR_HH_OLD +#define DUMUX_EL2P_LOCAL_OPERATOR_HH_OLD -#include<dune/common/version.hh> -#include<dune/geometry/quadraturerules.hh> +#warning this header is deprecated, use dumux/geomechanics/el2p/localoperator.hh instead -#include<dune/pdelab/localoperator/pattern.hh> -#include<dune/pdelab/localoperator/flags.hh> -#include<dune/pdelab/localoperator/defaultimp.hh> -#include<dune/pdelab/gridfunctionspace/localvector.hh> -#include<dune/pdelab/common/geometrywrapper.hh> -#include "el2pproperties.hh" - -namespace Dumux { - -namespace PDELab { - -/*! - * \brief A local operator for PDELab which wraps the contributions from - * el2plocalresidual (box discretized mass balances) - * and alphaMomentum (FE discretized momentum balance). - */ -template<class TypeTag> -class El2PLocalOperator - : - public Dune::PDELab::FullVolumePattern, - public Dune::PDELab::LocalOperatorDefaultFlags -{ - // copying the local operator for PDELab is not a good idea - El2PLocalOperator(const El2PLocalOperator &); - - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity::Geometry::JacobianInverseTransposed JacobianInverseTransposed; - typedef typename GridView::Intersection Intersection; - typedef typename Dune::PDELab::IntersectionGeometry<Intersection>::ctype DT; - - enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; - enum{dim = GridView::dimension}; - enum{dimWorld = GridView::dimensionworld}; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - - enum { - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx - }; - -public: - // pattern assembly flags - enum { doPatternVolume = true }; - - // residual assembly flags - enum { doAlphaVolume = true }; - - /*! - * \param model The physical model for the box scheme. - */ - El2PLocalOperator(Model &model) - : model_(model) - {} - - /*! - * \brief Volume integral depending on test and ansatz functions - * - * \tparam EG The entity geometry type from PDELab - * \tparam LFSU The type of the local function space of the ansatz functions - * \tparam X The type of the container for the coefficients for the ansatz functions - * \tparam LFSV The type of the local function space of the test functions - * \tparam R The range type (usually FieldVector<double>) - * - * \param eg The entity geometry object - * \param lfsu The local function space object of the ansatz functions - * \param x The object of the container for the coefficients for the ansatz functions - * \param lfsv The local function space object of the test functions - * \param r The object storing the volume integral - */ - template<typename EG, typename LFSU, typename X, typename LFSV, typename R> - void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, - const LFSV& lfsv, R& r) const - { - typedef typename LFSU::Traits::SizeType size_type; - - // evaluate the local residual of the box mass balance equation for the current element - model_.localResidual().eval(eg.entity()); - - // pressure and saturation local function space (mass balance equations) - typedef typename LFSU::template Child<0>::Type PressSatLFS; - // local function space for pressure - typedef typename PressSatLFS::template Child<0>::Type PressLFS; - const PressSatLFS& pressSatLFS = lfsu.template child<0>(); - const PressLFS& pressLFS = pressSatLFS.template child<0>(); - // local function space for saturation - typedef typename PressSatLFS::template Child<1>::Type SatLFS; - const SatLFS& satLFS = pressSatLFS.template child<1>(); - - unsigned int numScv = eg.entity().subEntities(dim); - - for (size_type i = 0; i < (numEq-dim) * numScv; i++) - { - // retrieve the local residual value for vertex=i%Vertices and equation i/numScv (here 0 or 1) - Scalar tmp = model_.localResidual().residual(i%numScv)[i/numScv]; - // get residual for brine phase mass balance equation - if(i < numScv) - r.rawAccumulate(pressLFS, i, tmp); - // get residual for CO2 phase mass balance equation - else - r.rawAccumulate(satLFS,i-numScv, tmp); - } - // get residual for momentum balance equation - alphaMomentum(eg, lfsu, x, lfsv, r); - } - - - /*! - * \brief Calculate the local residual of the momentum balance equation - * with the finite element method. This requires numerical - * integration which is done via a quadrature rule. - * - * \tparam EG The entity geometry type from PDELab - * \tparam LFSU The type of the local function space of the ansatz functions - * \tparam X The type of the container for the coefficients for the ansatz functions - * \tparam LFSV The type of the local function space of the test functions - * \tparam R The range type (usually FieldVector<double>) - * - * \param eg The entity geometry object - * \param lfsu The local function space object of the ansatz functions - * \param x The object of the container for the coefficients for the ansatz functions - * \param lfsv The local function space object of the test functions - * \param r The object storing the volume integral - * - * - */ - template<typename EG, typename LFSU, typename X, typename LFSV, typename R> - void alphaMomentum (const EG& eg, const LFSU& lfsu, const X& x, - const LFSV& lfsv, R& r) const - { - FVElementGeometry fvGeometry; - fvGeometry.update(model_.problem().gridView(), eg.entity()); - // retrieve lame parameters for calculation of effective stresses - const Dune::FieldVector<Scalar,2> lameParams = model_.problem().spatialParams().lameParams(eg.entity(), fvGeometry, 0); - Scalar lambda = lameParams[0]; - Scalar mu = lameParams[1]; - // retrieve materialParams for calculate of capillary pressure - const MaterialLawParams& materialParams = - model_.problem().spatialParams().materialLawParams(eg.entity(), fvGeometry, 0); - // retrieve initial porosity - Scalar porosity = model_.problem().spatialParams().porosity(eg.entity(), fvGeometry, 0); - - // order of quadrature rule - const int qorder = 3; - - // extract local function spaces - // pressure and saturation local function space (mass balance equations) - typedef typename LFSU::template Child<0>::Type PressSatLFS; - const PressSatLFS& pressSatLFS = lfsu.template child<0>(); - // local function space for pressure - typedef typename PressSatLFS::template Child<0>::Type PressLFS; - const PressLFS& pressLFS = pressSatLFS.template child<0>(); - const unsigned int pressSize = pressLFS.size(); - // local function space for saturation - typedef typename PressSatLFS::template Child<1>::Type SatLFS; - const SatLFS& satLFS = pressSatLFS.template child<1>(); - // local function space for solid displacement - typedef typename LFSU::template Child<1>::Type DisplacementLFS; - typedef typename DisplacementLFS::template Child<0>::Type DisplacementScalarLFS; - const DisplacementLFS& displacementLFS = lfsu.template child<1>(); - const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<0>(); - const unsigned int dispSize = displacementLFS.template child<0>().size(); - - // domain and range field type - typedef typename DisplacementScalarLFS::Traits::FiniteElementType:: - Traits::LocalBasisType::Traits::RangeFieldType RF; - typedef typename DisplacementScalarLFS::Traits::FiniteElementType:: - Traits::LocalBasisType::Traits::RangeType RT_V; - typedef typename DisplacementScalarLFS::Traits::FiniteElementType:: - Traits::LocalBasisType::Traits::JacobianType JacobianType_V; - typedef typename PressLFS::Traits::FiniteElementType:: - Traits::LocalBasisType::Traits::DomainFieldType DF; - typedef typename PressLFS::Traits::FiniteElementType:: - Traits::LocalBasisType::Traits::RangeType RT_P; - - // select quadrature rule for the element geometry type and with the order=qorder - const auto geometry = eg.geometry(); - Dune::GeometryType geomType = geometry.type(); - const Dune::QuadratureRule<DF,dim>& rule = Dune::QuadratureRules<DF,dim>::rule(geomType,qorder); - - // loop over quadrature points - for (typename Dune::QuadratureRule<DF,dim>::const_iterator it=rule.begin(); it!=rule.end(); ++it) - { - // evaluate reference element gradients of shape functions at quadrature point - // (we assume Galerkin method lfsu=lfsv) - std::vector<JacobianType_V> vGradRef(dispSize); - uScalarLFS.finiteElement().localBasis().evaluateJacobian(it->position(),vGradRef); - - - // get inverse transposed jacobian for quadrature point - const JacobianInverseTransposed jacobian = geometry.jacobianInverseTransposed(it->position()); - - // calculate shape function gradients at the quadrature point in global coordinates. This is done - // by multiplying the reference element shape functions with the inverse transposed jacobian - std::vector<Dune::FieldVector<RF,dim> > vGrad(dispSize); - for (size_t i = 0; i < dispSize; i++) - { - vGrad[i] = 0.0; - jacobian.umv(vGradRef[i][0],vGrad[i]); - } - - // calculate the gradient of the solid displacement vector uGrad - // x(uLFS,i) is the solid displacement entry of the solution vector - // for element vertex i and coordinate direction coordDir - - Dune::FieldMatrix<RF,dim,dim> uGrad(0.0); - for(int coordDir = 0; coordDir < dim; ++coordDir) { - const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); - // compute gradient of u - for (size_t i = 0; i < dispSize; i++) - uGrad[coordDir].axpy(x(uLFS,i),vGrad[i]); - } - // calculate the strain tensor epsilon - Dune::FieldMatrix<RF,dim,dim> epsilon; - for(int i = 0; i < dim; ++i) - for(int j = 0; j < dim; ++j) - epsilon[i][j] = 0.5*(uGrad[i][j] + uGrad[j][i]); - - RF traceEpsilon = 0; - for(int i = 0; i < dim; ++i) - traceEpsilon += epsilon[i][i]; - - // calculate the effective stress tensor effStress - Dune::FieldMatrix<RF,dim,dim> effStress(0.0); - for(int i = 0; i < dim; ++i) - { - effStress[i][i] = lambda*traceEpsilon; - for(int j = 0; j < dim; ++j) - effStress[i][j] += 2.0*mu*epsilon[i][j]; - } - - // retrieve the shape functions for interpolating the primary variables at the - // current quadrature point - std::vector<RT_P> q(pressSize); - pressLFS.finiteElement().localBasis().evaluateFunction(it->position(),q); - - RT_P pw(0.0); - RT_P sn(0.0); - RT_P ux(0.0); - RT_P uy(0.0); - RT_P uz(0.0); - - // interpolate primary variables at current quadrature point - for (size_t i = 0; i < pressLFS.size(); i++) - { - pw += x(pressLFS,i) * q[i]; - sn += x(satLFS,i) * q[i]; - ux += x(displacementLFS.child(0),i) * q[i]; - if (dim > 1) - uy += x(displacementLFS.child(1),i) * q[i]; - if (dim > 2) - uz += x(displacementLFS.child(2),i) * q[i]; - } - RT_P sw = 1.0 - sn; - RT_P pn = pw + MaterialLaw::pc(materialParams, sw); - RT_P pEff; - - const GlobalPosition& globalPos = geometry.global(it->position()); - - // calculate change in effective pressure with respect to initial conditions pInit (pInit is negativ) - pEff = pw*sw + pn*sn + model_.problem().pInit(globalPos, it->position(), eg.entity()); - RF uDiv = traceEpsilon; - RF porosityEff; - - // assume deformation induced porosity changes - if(model_.problem().coupled() == true){ - if (porosity + uDiv < 1e-3*porosity){ - DUNE_THROW(Dumux::NumericalProblem, "volume change too large"); - } - else - // this equation would be correct if the bulk volume could change (Vol_new = Vol_init * (1+div u)), however, we - // have a constant bulk volume therefore we should apply phi_eff = phi_init + div u - // but this causes convergence problems. Since div u is very small here the chosen relation is - // assumed to be a good approximation - porosityEff = (porosity + uDiv)/(1.0 + uDiv); - } - // neglect deformation induced porosity changes - else - porosityEff = porosity; - - // fill primary variable vector for current quadrature point - PrimaryVariables primVars; - - primVars[wPhaseIdx] = pw; - primVars[nPhaseIdx] = sn; - primVars[Indices::uxIdx] = ux; - if (dim > 1) - primVars[Indices::uyIdx] = uy; - if (dim > 2) - primVars[Indices::uzIdx] = uz; - - VolumeVariables volVars; - // evaluate volume variables for this quadrature point - // TODO / NOTE: this overwrites the entries of the volumevariables of node 0 - // and can cause errors - volVars.update(primVars, model_.problem(), eg.entity(), fvGeometry, 0, false); - - // calculate the density difference for the gravity term - RF rhoDiff = volVars.density(nPhaseIdx) - volVars.density(wPhaseIdx); - - // geometric weight need for quadrature rule evaluation (numerical integration) - RF qWeight = it->weight() * geometry.integrationElement(it->position()); - - // evaluate basis functions - std::vector<RT_V> vBasis(dispSize); - displacementLFS.child(0).finiteElement().localBasis().evaluateFunction(it->position(), vBasis); - - for(int coordDir = 0; coordDir < dim; ++coordDir) { - const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); - // assemble momentum balance equation - for (size_t i = 0; i < dispSize; i++){ - // multiply effective stress with gradient of weighting function and geometric weight of quadrature rule - Scalar tmp = (effStress[coordDir] * vGrad[i]) * qWeight; - r.rawAccumulate(uLFS,i,tmp); - - // subtract effective pressure change contribution multiplied with gradient of weighting function - // and geometric weight of quadrature rule (soil mechanics sign conventions, compressive stresses are negative) - tmp = -(pEff * vGrad[i][coordDir]) * qWeight; - r.rawAccumulate(uLFS,i,tmp); - - // evaluate gravity term (soil mechanics sign conventions, compressive stresses are negative) - // multiplied with weighting function and geometric weight of quadrature rule. - // This assumes that the solid phase density remains constant, that the changes in porosity are very small, - // and that the density of the brine phase remains constant - tmp = sn*porosityEff*rhoDiff*model_.problem().gravity()[coordDir]*vBasis[i]* qWeight; - r.rawAccumulate(uLFS,i,tmp); - } - } - } - // include boundary conditions - // iterate over element intersections of codim dim-1 - for (const auto& intersection : Dune::intersections(model_.problem().gridView(), eg.entity())) - { - // handle only faces on the boundary - if (!intersection.boundary()) - continue; - - // select quadrature rule for intersection faces (dim-1) - Dune::GeometryType gtface = intersection.geometryInInside().type(); - const Dune::QuadratureRule<DF,dim-1>& faceRule = Dune::QuadratureRules<DF,dim-1>::rule(gtface,qorder); - - // get face index of this intersection - int fIdx = intersection.indexInInside(); - // get dimension of face - const int dimIs = Dune::PDELab::IntersectionGeometry<Intersection>::Entity::Geometry::mydimension; - - // get reference element for intersection geometry (reference element for face if dim = 3) - const Dune::ReferenceElement<DT,dimIs>& refElement = Dune::ReferenceElements<DT,dimIs>::general(geomType); - // get reference element for edges of intersection geometry (reference element for edge if dim = 3), needed for Dirichlet BC - const Dune::ReferenceElement<DT,dimIs-1> &face_refElement = - Dune::ReferenceElements<DT,dimIs-1>::general(intersection.geometryInInside().type()); - - // Treat Neumann boundary conditions - // loop over quadrature points and integrate normal stress changes (traction changes) - for (typename Dune::QuadratureRule<DF,dim-1>::const_iterator it=faceRule.begin(); it!=faceRule.end(); ++it) - { - // position of quadrature point in local coordinates of element - DimVector local = intersection.geometryInInside().global(it->position()); - - GlobalPosition globalPos = geometry.global(local); - - // evaluate boundary condition type - BoundaryTypes boundaryTypes; - model_.problem().boundaryTypesAtPos(boundaryTypes, globalPos); - - // skip rest if we are on Dirichlet boundary - if (!boundaryTypes.hasNeumann()) - continue; - - // evaluate basis functions of all all element vertices for quadrature point location "local" - std::vector<RT_V> vBasis(dispSize); - displacementLFS.child(0).finiteElement().localBasis().evaluateFunction(local, vBasis); - - // evaluate stress boundary condition. The stress change is assumed to be in normal direction (i.e. traction) - PrimaryVariables traction; - model_.problem().neumannAtPos(traction, globalPos); - - // get quadrature rule weight for intersection - const RF qWeight = it->weight() * intersection.geometry().integrationElement(it->position()); - - for(unsigned int coordDir=0; coordDir<dim; ++coordDir){ - const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); - // get the traction values for the current quadrature point, - // multiply it with the basis function and the quadrature rule weight - // and add it to the residual - if (boundaryTypes.isNeumann(Indices::momentum(coordDir))) - for (size_t i = 0; i < dispSize; i++){ - Scalar tmp = -traction[Indices::momentum(coordDir)] * vBasis[i] * qWeight; - r.rawAccumulate(uLFS,i,tmp); - } - - } - } - - // Treat Dirichlet boundary conditions, for Dirichlet boundaries we need to check vertices - // first do loop over degrees of freedom for displacement vector entry, then check codim of this degree of freedom - // then do loop over the current intersection face for the degrees of freedom with the given codim - // compare the subentity of the element loop with the subentity of the intersection face loop - // if the subentities are identical retrieve the coordinates of the intersection face subentity and evaluate the boundary - // condition type and if it is a Dirichlet boundary condition then retrieve the Dirichlet value. - // subtract the Dirichlet value from the corresponding solution vector entry (for this the outer element loop is needed) - // and also subtract the residual value which has already been calculated for this degree of freedom - // write the result into the residual - - for(unsigned int coordDir=0; coordDir<dim; ++coordDir){ - const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); - - // loop over number of element vertices - for (size_t i = 0; i < dispSize; i++) - { - // Get the codim to which this degree of freedom is attached to (should be a vertex) - unsigned int codim = displacementLFS.child(0).finiteElement().localCoefficients().localKey(i).codim(); - // if we are within the element do nothing (this could happen if second order approximations are applied) - if (codim==0) continue; - - // iterate over number of degrees of freedom with the given codim which are attached to the current intersection face - for (int j = 0; j < refElement.size(fIdx,1,codim); j++) - { // check if degree of freedom is located on a vertex of the current intersection (boundary face) - if (displacementLFS.child(0).finiteElement().localCoefficients().localKey(i).subEntity() == - refElement.subEntity(fIdx,1,j,codim)) - { - // get local coordinate for this degree of freedom -// this doesn't work: DimVector local = intersection.geometryInInside().global(face_refElement.position(j,codim-1)); - DimVector local = refElement.template geometry<1>(fIdx).global(face_refElement.position(j, codim-1)); - - GlobalPosition globalPos = geometry.global(local); - - // evaluate boundary condition type - BoundaryTypes boundaryTypes; - model_.problem().boundaryTypesAtPos(boundaryTypes, globalPos); - - if (boundaryTypes.isDirichlet(Indices::u(coordDir))) - { - // set value of dirichlet BC - PrimaryVariables dirichletValues; - model_.problem().dirichletAtPos(dirichletValues, globalPos); - // retrieve residual value which has already been calculated for the given vertex before it - // was clear that we are on a Dirichlet boundary - Scalar tmpResVal = r.container().base()[(numEq-dim)*dispSize + coordDir*dispSize + i]; - // subtract the dirichletValue and the stored residual value from the solution vector entry - // if the solution vector entry equals the dirichletValue the residual will be zero - Scalar tmp = x(uLFS,i) - dirichletValues[Indices::u(coordDir)] - tmpResVal; - // write result into the residual vector - r.rawAccumulate(uLFS,i,tmp); - } - } - } - } - } - } - } - - /*! - * \brief Jacobian of volume term - * - * \tparam EG The entity geometry type from PDELab - * \tparam LFSU The type of the local function space of the ansatz functions - * \tparam X The type of the container for the coefficients for the ansatz functions - * \tparam LFSV The type of the local function space of the test functions - * \tparam M The matrix type - * - * \param eg The entity geometry object - * \param lfsu The local function space object of the ansatz functions - * \param x The object of the container for the coefficients for the ansatz functions - * \param lfsv The local function space object of the test functions - * \param mat The object containing the local jacobian matrix - */ - template<typename EG, typename LFSU, typename X, typename LFSV, typename M> - void jacobian_volume (const EG& eg, - const LFSU& lfsu, - const X& x, - const LFSV& lfsv, - M& mat) const - { - typedef typename LFSU::Traits::SizeType size_type; - - model_.localJacobian().assemble(eg.entity()); - // pressure and saturation local function space (mass balance equations) - typedef typename LFSU::template Child<0>::Type PressSatLFS; - typedef typename PressSatLFS::template Child<0>::Type PressLFS; - const PressSatLFS& pressSatLFS = lfsu.template child<0>(); - const PressLFS& pressLFS = pressSatLFS.template child<0>(); - typedef typename PressSatLFS::template Child<1>::Type SatLFS; - const SatLFS& satLFS = pressSatLFS.template child<1>(); - // local function space for solid displacement - typedef typename LFSU::template Child<1>::Type DisplacementLFS; - typedef typename DisplacementLFS::template Child<0>::Type DisplacementScalarLFS; - const DisplacementLFS& displacementLFS = lfsu.template child<1>(); - - // type of local residual vector - typedef typename M::value_type R; - typedef Dune::PDELab::LocalVector<R> LocalResidualVector; - typedef Dune::PDELab::WeightedVectorAccumulationView<LocalResidualVector> ResidualView; - - unsigned int numScv = eg.entity().subEntities(dim); - - // loop over all degrees of freedom of the current element - for (size_type j = 0; j < numScv*numEq; j++) - { - // assemble entries for mass balance equations - for (size_type i = 0; i < (numEq-dim)*numScv; i++) - { - // local jacobian value of location idxI=i%numScv, idxJ=j%numScv for equation i/numScv and unknown j/numScv - Scalar tmp = (model_.localJacobian().mat(i%numScv,j%numScv))[i/numScv][j/numScv]; - // mass balance entries for pressure - if (j < numScv){ - if(i < numScv) - mat.rawAccumulate(pressLFS,i,pressLFS,j,tmp); - else - mat.rawAccumulate(satLFS,i-numScv,pressLFS,j,tmp); - } - // mass balance entries for saturation - else if (j < 2*numScv){ - if(i < numScv) - mat.rawAccumulate(pressLFS,i,satLFS,j-numScv,tmp); - else - mat.rawAccumulate(satLFS,i-numScv,satLFS,j-numScv,tmp); - } - // mass balance entries for solid displacement in x-direction - else if (j < 3*numScv) - { - const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<0>(); - if(i < numScv) - mat.rawAccumulate(pressLFS,i,uScalarLFS,j-2*numScv,tmp); - else - mat.rawAccumulate(satLFS,i-numScv,uScalarLFS,j-2*numScv,tmp); - } - // mass balance entries for solid displacement in y-direction - else if (j < 4*numScv && dim >=2) - { - const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<1>(); - if(i < numScv) - mat.rawAccumulate(pressLFS,i,uScalarLFS,j-3*numScv,tmp); - else - mat.rawAccumulate(satLFS,i-numScv,uScalarLFS,j-3*numScv,tmp); - } - // mass balance entries for solid displacement in z-direction - else if(j < 5*numScv && dim >=3) - { - const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<dim-1>(); - if(i < numScv) - mat.rawAccumulate(pressLFS,i,uScalarLFS,j-(numEq-1)*numScv,tmp); - else - mat.rawAccumulate(satLFS,i-numScv,uScalarLFS,j-(numEq-1)*numScv,tmp); - } - - } - } - - // calculate local jacobian entries and assemble for momentum balance equation - const int m=lfsv.size(); - const int n=lfsu.size(); - - X u(x); - LocalResidualVector down(mat.nrows(),0); - - // evaluate momentum residual for momentum balance equation - ResidualView downView = down.weightedAccumulationView(1.0); - alphaMomentum(eg, lfsu, u, lfsv, downView); - - // loop over all columns (number of element vertices * number of equations) - for (int j = 0; j < n; j++) - { - // vary the solution vector entry (lfsu,j) by a small value delta (forward differencing) - // this comprises presure, saturation, ux, uy and uz - Scalar delta = 1e-4*(1.0+std::abs(u(lfsu,j))); - u(lfsu,j) += delta; - - // evaluate momentum balance residual for the varied solution vector - LocalResidualVector up(mat.nrows(), 0); - ResidualView upView = up.weightedAccumulationView(1.0); - alphaMomentum(eg, lfsu, u, lfsv, upView); - - // calculate partial derivative for momentum balance equations and assemble - for (int i = (numEq-dim)*numScv; i < m; i++) - { - Scalar entry = (up(lfsv, i) - down(lfsv, i))/delta; - // accumulate resulting partial derivatives into jacobian - mat.rawAccumulate(lfsv,i, lfsu,j,entry); - } - - // reset solution - u(lfsu,j) = x(lfsu,j); - } - } - -private: - Model& model_; -}; - -} // namespace PDELab -} // namespace Dumux +#include <dumux/geomechanics/el2p/localoperator.hh> #endif diff --git a/dumux/geomechanics/el2p/el2plocalresidual.hh b/dumux/geomechanics/el2p/el2plocalresidual.hh index b584fc3e2f593bd666eb81333a48e5ad031b0a41..e6cf28856cb5d4a1e410af090ab1308399879519 100644 --- a/dumux/geomechanics/el2p/el2plocalresidual.hh +++ b/dumux/geomechanics/el2p/el2plocalresidual.hh @@ -1,317 +1,8 @@ -// -*- 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 Element-wise calculation of the residual for the linear elastic, - * two-phase model in the fully implicit scheme. - */ -#ifndef DUMUX_ELASTIC2P_LOCAL_RESIDUAL_HH -#define DUMUX_ELASTIC2P_LOCAL_RESIDUAL_HH +#ifndef DUMUX_ELASTIC2P_LOCAL_RESIDUAL_HH_OLD +#define DUMUX_ELASTIC2P_LOCAL_RESIDUAL_HH_OLD -#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> -#include <dumux/implicit/box/localresidual.hh> -#include "el2pproperties.hh" +#warning this header is deprecated, use dumux/geomechanics/el2p/localresidual.hh instead -namespace Dumux { -/*! - * \ingroup ElTwoPModel - * \ingroup ImplicitLocalResidual - * - * \brief Element-wise calculation of the Jacobian matrix for problems - * using the two-phase linear-elasticity fully implicit model. - */ -template<class TypeTag> -class ElTwoPLocalResidual: public BoxLocalResidual<TypeTag> { -protected: - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; +#include <dumux/geomechanics/el2p/localresidual.hh> - enum { - dim = GridView::dimension - }; - - typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - typedef Dune::FieldVector<Scalar, dim> DimVector; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum { - numFluidPhases = GET_PROP_VALUE(TypeTag, NumPhases) - }; - enum { - contiWEqIdx = Indices::contiWEqIdx, - contiNEqIdx = Indices::contiNEqIdx, - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx - }; - //TODO: delete this if not required - // only effective porosity update in element variables doesn't work - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; - typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; - -public: - /*! - * \brief Constructor. Sets the upwind weight. - */ - ElTwoPLocalResidual() { - // retrieve the upwind weight for the mass conservation equations. Use the value - // specified via the property system as default, and overwrite - // it by the run-time parameter from the Dune::ParameterTree - massUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, - MassUpwindWeight); - } - ; - - /*! - * \brief Evaluate the amount all conservation quantities - * (e.g. phase mass) within a finite sub-control volume. - * - * \param storage The phase mass within the sub-control volume - * \param scvIdx The SCV (sub-control-volume) index - * \param usePrevSol Evaluate function with solution of current or previous time step - */ - void computeStorage(PrimaryVariables &storage, int scvIdx, - bool usePrevSol) const { - // if flag usePrevSol is set, the solution from the previous - // time step is used, otherwise the current solution is - // used. The secondary variables are used accordingly. This - // is required to compute the derivative of the storage term - // using the implicit Euler method. - const ElementVolumeVariables &elemVolVars = - usePrevSol ? this->prevVolVars_() : this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[scvIdx]; - - storage = Scalar(0); - - // wetting phase mass - storage[contiWEqIdx] = volVars.density(wPhaseIdx) - * volVars.saturation(wPhaseIdx) * volVars.effPorosity; - // non-wetting phase mass - storage[contiNEqIdx] = volVars.density(nPhaseIdx) - * volVars.saturation(nPhaseIdx) * volVars.effPorosity; - } - - /*! - * \brief Evaluates the mass flux over a face of a sub-control - * volume. - * - * \param flux The flux over the SCV (sub-control-volume) face for each phase - * \param fIdx The index of the SCV face - * \param onBoundary A boolean variable to specify whether the flux variables - * are calculated for interior SCV faces or boundary faces, default=false - */ - void computeFlux(PrimaryVariables &flux, int fIdx, - const bool onBoundary = false) const { - //TODO: delete this if not required - // adapts the effective porosity node-wise for evaluation of derivatives. - // At the moment computeFlux is called before computeStorage so effPorosity in - // computeStorage should also be correct. - -// if (fIdx == 0) -// { -// int numScv = this->element_().template count<dim> (); -// -// LocalFunctionSpace localFunctionSpace(this->problem_().model().jacobianAssembler().gridFunctionSpace()); -// localFunctionSpace.bind(this->element_()); -// std::vector<Scalar> values; -// localFunctionSpace.vread(this->problem_().model().curSol(), values); -// -// -// typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; -// const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); -// const unsigned int dispSize = displacementLFS.child(0).size(); -// -// typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; -// typedef typename ScalarDispLFS::Traits::FiniteElementType:: -// Traits::LocalBasisType::Traits::JacobianType JacobianType_V; -// typedef typename ScalarDispLFS::Traits::FiniteElementType:: -// Traits::LocalBasisType::Traits::RangeFieldType RF; -// typedef typename ScalarDispLFS::Traits::FiniteElementType:: -// Traits::LocalBasisType::Traits::DomainFieldType DF; -// -// // calculate the divergence of the displacement -// for (int scvIdx = 0; scvIdx < numScv; scvIdx++) -// { -// const DimVector& scvCenter = this->fvGeometry_().subContVol[scvIdx].localCenter; -// -// // evaluate gradient of displacement shape functions -// std::vector<JacobianType_V> vRefShapeGradient(dispSize); -// displacementLFS.child(0).finiteElement().localBasis().evaluateJacobian(scvCenter, vRefShapeGradient); -// -// // transform gradient to physical element -// const Dune::FieldMatrix<DF,dim,dim> jacInvT = this->element_().geometry().jacobianInverseTransposed(scvCenter); -// std::vector<Dune::FieldVector<RF,dim> > vShapeGradient(dispSize); -// for (size_t i = 0; i < dispSize; i++) -// { -// vShapeGradient[i] = 0.0; -// jacInvT.umv(vRefShapeGradient[i][0],vShapeGradient[i]); -// } -// -// // calculate gradient of current displacement -// typedef Dune::FieldMatrix<RF, dim, dim> Tensor; -// Tensor uGradient(0.0); -// for(int comp = 0; comp < dim; ++comp){ -// const ScalarDispLFS & scalarDispLFS = displacementLFS.child(comp); -// -// for (size_t i = 0; i < 8; i++) -// uGradient[comp].axpy(this->curVolVars_()[i].displacement(comp), vShapeGradient[i]); -// -// for (size_t i = 8; i < scalarDispLFS.size(); i++) -// uGradient[comp].axpy(values[scalarDispLFS.localIndex(i)], vShapeGradient[i]); -// } -// -// this->curVolVars_()[scvIdx].divU = 0.0; -// for (int comp = 0; comp < dim; comp++) -// this->curVolVars_()[scvIdx].divU += uGradient[comp][comp]; -// if(this->problem_().coupled() == true){ -// if (this->curVolVars_()[scvIdx].divU < - this->curVolVars_()[scvIdx].porosity()){ -// this->curVolVars_()[scvIdx].effPorosity = this->curVolVars_()[scvIdx].porosity(); -// std::cout<<"volume change too large"<<std::endl; -// } -// else{ -// this->curVolVars_()[scvIdx].effPorosity = (this->curVolVars_()[scvIdx].porosity() -// + this->curVolVars_()[scvIdx].divU)/(1.0 + this->curVolVars_()[scvIdx].divU);} -// } -// else -// this->curVolVars_()[scvIdx].effPorosity = this->curVolVars_()[scvIdx].porosity(); -// } -// } - - FluxVariables fluxVars(this->problem_(), this->element_(), - this->fvGeometry_(), fIdx, this->curVolVars_()); - - flux = 0; - this->computeAdvectiveFlux(flux, fluxVars); - } - - /*! - * \brief Evaluates the advective mass flux of all components over - * a face of a sub-control volume. - * - * \param flux The advective flux over the sub-control-volume face for each phase - * \param fluxVars The flux variables at the current SCV - * - * This method is called by compute flux and is mainly there for - * derived models to ease adding equations selectively. - */ - void computeAdvectiveFlux(PrimaryVariables &flux, - const FluxVariables &fluxVars) const { - // calculate effective permeability based on effective porosity - // according to the relation given in Rutqvist and Tsang (2002) - // this evaluation should be moved to another location - DimVector tmpVec; - DimMatrix Keff, Keff_i, Keff_j; - - Scalar exp_i, exp_j; - // evaluate effective permeabilities for nodes i and j based on the - // effective porosities, the initial porosities and the initial permeabilities - exp_i = - 22.2 - * (this->curVolVars_()[fluxVars.face().i].effPorosity - / this->curVolVars_()[fluxVars.face().i].porosity() - - 1); - exp_j = - 22.2 - * (this->curVolVars_()[fluxVars.face().j].effPorosity - / this->curVolVars_()[fluxVars.face().j].porosity() - - 1); - Keff_i = fluxVars.intrinsicPermeability(); - Keff_i *= exp(exp_i); - Keff_j = fluxVars.intrinsicPermeability(); - Keff_j *= exp(exp_j); - - // calculate the mean effective permeability at integration point - this->problem_().spatialParams().meanK(Keff, Keff_i, Keff_j); - - // loop over all phases - for (int phaseIdx = 0; phaseIdx < numFluidPhases; ++phaseIdx) { - // data attached to upstream and the downstream vertices - // of the current phase - // calculate the flux in the normal direction of the - // current sub control volume face - - // if geomechanical feedback on flow is taken into account the effective permeability is - // applied for the flux calculations - if (this->problem_().coupled() == true) { - Keff.mv(fluxVars.potentialGrad(phaseIdx), tmpVec); - } else { - fluxVars.intrinsicPermeability().mv( - fluxVars.potentialGrad(phaseIdx), tmpVec); - } - Scalar normalFlux = -(tmpVec * fluxVars.face().normal); - - // data attached to upstream and the downstream vertices - // of the current phase - const VolumeVariables &up = this->curVolVars_( - fluxVars.upstreamIdx(phaseIdx)); - const VolumeVariables &dn = this->curVolVars_( - fluxVars.downstreamIdx(phaseIdx)); - - // add advective flux of current phase - int eqIdx = (phaseIdx == wPhaseIdx) ? contiWEqIdx : contiNEqIdx; - flux[eqIdx] += normalFlux - * ((massUpwindWeight_) * up.density(phaseIdx) - * up.mobility(phaseIdx) - + (massUpwindWeight_) * dn.density(phaseIdx) - * dn.mobility(phaseIdx)); - - // if geomechanical feedback on flow is taken into account add the flux contribution - // of the displacement velocity - - if (this->problem_().coupled() == true) { - // use upwind displacement velocity to calculate phase transport (?) - flux[eqIdx] += up.effPorosity * up.saturation(phaseIdx) - * up.density(phaseIdx) * fluxVars.timeDerivUNormal(); - } - - } - } - - /*! - * \brief Calculate the source term of the equation - * - * \param q The source/sink in the SCV for each phase - * \param scvIdx The index of the SCV - * - */ - void computeSource(PrimaryVariables &q, int scvIdx) { - // retrieve the source term intrinsic to the problem - this->problem_().source(q, this->element_(), this->fvGeometry_(), - scvIdx); - } - -protected: - Implementation *asImp_() { - return static_cast<Implementation *>(this); - } - const Implementation *asImp_() const { - return static_cast<const Implementation *>(this); - } - -private: - Scalar massUpwindWeight_; -}; -} #endif diff --git a/dumux/geomechanics/el2p/el2pmodel.hh b/dumux/geomechanics/el2p/el2pmodel.hh index bac40d5d7c4c1a9001bffe13c65e3fed007c0555..c3d2ffb9bb351539dd07ba72a21c96a92aff0c87 100644 --- a/dumux/geomechanics/el2p/el2pmodel.hh +++ b/dumux/geomechanics/el2p/el2pmodel.hh @@ -1,714 +1,8 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * See the file COPYING for full copying permissions. * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ +#ifndef DUMUX_ELASTIC2P_MODEL_HH_OLD +#define DUMUX_ELASTIC2P_MODEL_HH_OLD -/*! -* \file -* -* \brief Adaption of the fully implicit scheme to the two-phase linear elasticity model. -*/ +#warning this header is deprecated, use dumux/geomechanics/el2p/model.hh instead -#ifndef DUMUX_ELASTIC2P_MODEL_HH -#define DUMUX_ELASTIC2P_MODEL_HH +#include <dumux/geomechanics/el2p/model.hh> -#include <dune/pdelab/gridfunctionspace/interpolate.hh> -#include <dumux/common/eigenvalues.hh> -#include "el2pproperties.hh" - -namespace Dumux { - -namespace Properties { -NEW_PROP_TAG(InitialDisplacement); //!< The initial displacement function -NEW_PROP_TAG(InitialPressSat); //!< The initial pressure and saturation function -} - -/*! - * \ingroup ElTwoPBoxModel - * \brief Adaption of the fully implicit scheme to the two-phase linear elasticity model. - * - * This model implements a two-phase flow of compressible immiscible fluids \f$\alpha \in \{ w, n \}\f$. - * The deformation of the solid matrix is described with a quasi-stationary momentum balance equation. - * The influence of the pore fluid is accounted for through the effective stress concept (Biot 1941). - * The total stress acting on a rock is partially supported by the rock matrix and partially supported - * by the pore fluid. The effective stress represents the share of the total stress which is supported - * by the solid rock matrix and can be determined as a function of the strain according to Hooke's law. - * - * As an equation for the conservation of momentum within the fluid phases the standard multiphase Darcy's approach is used: - \f[ - v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \textbf{K} - \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} {\textbf g} \right) - \f] - * - * Gravity can be enabled or disabled via the property system. - * By inserting this into the continuity equation, one gets -\f[ - \frac{\partial \phi_{eff} \varrho_\alpha S_\alpha}{\partial t} - - \text{div} \left\{ \varrho_\alpha \frac{k_{r\alpha}}{\mu_\alpha} - \mathbf{K}_\text{eff} \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mathbf{g} \right) - - \phi_{eff} \varrho_\alpha S_\alpha \frac{\partial \mathbf{u}}{\partial t} - \right\} - q_\alpha = 0 \;, - \f] - * - * - * A quasi-stationary momentum balance equation is solved for the changes with respect to the initial conditions (Darcis 2012), note - * that this implementation assumes the soil mechanics sign convention (i.e. compressive stresses are negative): - \f[ - \text{div}\left( \boldsymbol{\Delta \sigma'}- \Delta p_{eff} \boldsymbol{I} \right) + \Delta \varrho_b {\textbf g} = 0 \;, - \f] - * with the effective stress: - \f[ - \boldsymbol{\sigma'} = 2\,G\,\boldsymbol{\epsilon} + \lambda \,\text{tr} (\boldsymbol{\epsilon}) \, \mathbf{I}. - \f] - * - * and the strain tensor \f$\boldsymbol{\epsilon}\f$ as a function of the solid displacement gradient \f$\textbf{grad} \mathbf{u}\f$: - \f[ - \boldsymbol{\epsilon} = \frac{1}{2} \, (\textbf{grad} \mathbf{u} + \textbf{grad}^T \mathbf{u}). - \f] - * - * Here, the rock mechanics sign convention is switch off which means compressive stresses are < 0 and tensile stresses are > 0. - * The rock mechanics sign convention can be switched on for the vtk output via the property system. - * - * The effective porosity and the effective permeability are calculated as a function of the solid displacement: - \f[ - \phi_{eff} = \frac{\phi_{init} + \text{div} \mathbf{u}}{1 + \text{div} \mathbf{u}} - \f] - \f[ - K_{eff} = K_{init} \text{exp}\left( 22.2(\phi_{eff}/\phi_{init} -1 )\right) - \f] - * The mass balance equations are discretized using a vertex-centered finite volume (box) - * or cell-centered finite volume scheme as spatial and the implicit Euler method as time discretization. - * The momentum balance equations are discretized using a standard Galerkin Finite Element method as - * spatial discretization scheme. - * - * - * The primary variables are the wetting phase pressure \f$p_w\f$, the nonwetting phase saturation \f$S_n\f$ and the solid - * displacement vector \f$\mathbf{u}\f$ (changes in solid displacement with respect to initial conditions). - */ -template<class TypeTag> -class ElTwoPModel: public GET_PROP_TYPE(TypeTag, BaseModel) -{ - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - numEq = GET_PROP_VALUE(TypeTag, NumEq), - nPhaseIdx = Indices::nPhaseIdx, - wPhaseIdx = Indices::wPhaseIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld - }; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename Element::Geometry::JacobianInverseTransposed JacobianInverseTransposed; - - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; - typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; - -public: - - /*! - * \brief Write the current solution to a restart file. - * - * \param outStream The output stream of one vertex for the restart file - * \param entity The Entity - * - * Due to the mixed discretization schemes which are combined via pdelab for this model - * the solution vector has a different form than in the pure box models - * it sorts the primary variables in the following way: - * p_vertex0 S_vertex0 p_vertex1 S_vertex1 p_vertex2 ....p_vertexN S_vertexN - * ux_vertex0 uy_vertex0 uz_vertex0 ux_vertex1 uy_vertex1 uz_vertex1 ... - * - * Therefore, the serializeEntity function has to be modified. - */ - template <class Entity> - void serializeEntity(std::ostream &outStream, - const Entity &entity) - { - // vertex index - int dofIdxGlobal = this->dofMapper().index(entity); - - // write phase state - if (!outStream.good()) { - DUNE_THROW(Dune::IOError, - "Could not serialize vertex " - << dofIdxGlobal); - } - int numScv = this->gridView().size(dim); - // get p and S entries for this vertex - for (int eqIdx = 0; eqIdx < numEq-dim; ++eqIdx) { - outStream << this->curSol().base()[dofIdxGlobal*(numEq-dim) + eqIdx][0]<<" "; - } - // get ux, uy, uz entries for this vertex - for (int j = 0; j< dim; ++j) - outStream << this->curSol().base()[numScv*(numEq-dim) + dofIdxGlobal*dim + j][0] <<" "; - - int vIdxGlobal = this->dofMapper().index(entity); - if (!outStream.good()) - DUNE_THROW(Dune::IOError, "Could not serialize vertex " << vIdxGlobal); - } - - /*! - * \brief Reads the current solution for a vertex from a restart - * file. - * - * \param inStream The input stream of one vertex from the restart file - * \param entity The Entity - * - * Due to the mixed discretization schemes which are combined via pdelab for this model - * the solution vector has a different form than in the pure box models - * it sorts the primary variables in the following way: - * p_vertex0 S_vertex0 p_vertex1 S_vertex1 p_vertex2 ....p_vertexN S_vertexN - * ux_vertex0 uy_vertex0 uz_vertex0 ux_vertex1 uy_vertex1 uz_vertex1 ... - * - * Therefore, the deserializeEntity function has to be modified. - */ - template<class Entity> - void deserializeEntity(std::istream &inStream, const Entity &entity) - { - int dofIdxGlobal = this->dofMapper().index(entity); - - if (!inStream.good()){ - DUNE_THROW(Dune::IOError, - "Could not deserialize vertex " - << dofIdxGlobal); - } - int numScv = this->gridView().size(dim); - for (int eqIdx = 0; eqIdx < numEq-dim; ++eqIdx) { - // read p and S entries for this vertex - inStream >> this->curSol().base()[dofIdxGlobal*(numEq-dim) + eqIdx][0];} - for (int j = 0; j< dim; ++j){ - // read ux, uy, uz entries for this vertex - inStream >> this->curSol().base()[numScv*(numEq-dim) + dofIdxGlobal*dim + j][0];} - } - - - /*! - * \brief \copybrief ImplicitModel::addOutputVtkFields - * - * Specialization for the ElOnePTwoCBoxModel, add one-phase two-component - * properties, solid displacement, stresses, effective properties and the - * process rank to the VTK writer. - */ - template<class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, MultiWriter &writer) { - // check whether compressive stresses are defined to be positive - // (rockMechanicsSignConvention_ == true) or negative - rockMechanicsSignConvention_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Vtk, RockMechanicsSignConvention); - - typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; - typedef Dune::BlockVector<Dune::FieldVector<double, dim> > VectorField; - - // create the required scalar and vector fields - unsigned numVertices = this->gridView_().size(dim); - unsigned numElements = this->gridView_().size(0); - - // create the required fields for vertex data - ScalarField &pw = *writer.allocateManagedBuffer(numVertices); - ScalarField &pn = *writer.allocateManagedBuffer(numVertices); - ScalarField &pc = *writer.allocateManagedBuffer(numVertices); - ScalarField &sw = *writer.allocateManagedBuffer(numVertices); - ScalarField &sn = *writer.allocateManagedBuffer(numVertices); - VectorField &displacement = *writer.template allocateManagedBuffer<Scalar, dim>(numVertices); - ScalarField &rhoW = *writer.allocateManagedBuffer(numVertices); - ScalarField &rhoN = *writer.allocateManagedBuffer(numVertices); - ScalarField &Te = *writer.allocateManagedBuffer(numVertices); - - // create the required fields for element data - // effective stresses - VectorField &deltaEffStressX = *writer.template allocateManagedBuffer<Scalar, - dim>(numElements); - VectorField &deltaEffStressY = *writer.template allocateManagedBuffer<Scalar, - dim>(numElements); - VectorField &deltaEffStressZ = *writer.template allocateManagedBuffer<Scalar, - dim>(numElements); - // total stresses - VectorField &totalStressX = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - VectorField &totalStressY = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - VectorField &totalStressZ = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - // initial stresses - VectorField &initStressX = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - VectorField &initStressY = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - VectorField &initStressZ = *writer.template allocateManagedBuffer< - Scalar, dim>(numElements); - // principal stresses - ScalarField &principalStress1 = *writer.allocateManagedBuffer( - numElements); - ScalarField &principalStress2 = *writer.allocateManagedBuffer( - numElements); - ScalarField &principalStress3 = *writer.allocateManagedBuffer( - numElements); - - - ScalarField &effKx = *writer.allocateManagedBuffer(numElements); - ScalarField &effPorosity = *writer.allocateManagedBuffer(numElements); - ScalarField &effectivePressure = *writer.allocateManagedBuffer(numElements); - ScalarField &deltaEffPressure = *writer.allocateManagedBuffer(numElements); - - - ScalarField &Pcrtens = *writer.allocateManagedBuffer(numElements); - ScalarField &Pcrshe = *writer.allocateManagedBuffer(numElements); - - // initialize cell stresses, cell-wise hydraulic parameters and cell pressure with zero - - - for (unsigned int eIdx = 0; eIdx < numElements; ++eIdx) { - deltaEffStressX[eIdx] = Scalar(0.0); - if (dim >= 2) - deltaEffStressY[eIdx] = Scalar(0.0); - if (dim >= 3) - deltaEffStressZ[eIdx] = Scalar(0.0); - - totalStressX[eIdx] = Scalar(0.0); - if (dim >= 2) - totalStressY[eIdx] = Scalar(0.0); - if (dim >= 3) - totalStressZ[eIdx] = Scalar(0.0); - - initStressX[eIdx] = Scalar(0.0); - if (dim >= 2) - initStressY[eIdx] = Scalar(0.0); - if (dim >= 3) - initStressZ[eIdx] = Scalar(0.0); - - principalStress1[eIdx] = Scalar(0.0); - if (dim >= 2) - principalStress2[eIdx] = Scalar(0.0); - if (dim >= 3) - principalStress3[eIdx] = Scalar(0.0); - - effPorosity[eIdx] = Scalar(0.0); - effKx[eIdx] = Scalar(0.0); - effectivePressure[eIdx] = Scalar(0.0); - deltaEffPressure[eIdx] = Scalar(0.0); - - Pcrtens[eIdx] = Scalar(0.0); - Pcrshe[eIdx] = Scalar(0.0); - } - - ScalarField &rank = *writer.allocateManagedBuffer(numElements); - - - FVElementGeometry fvGeometry; - ElementVolumeVariables elemVolVars; - - const GridFunctionSpace& gridFunctionSpace = this->problem_().model().jacobianAssembler().gridFunctionSpace(); - const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); - // initialize start and end of element iterator - // loop over all elements (cells) - for (const auto& element : Dune::elements(this->gridView_())) { - if(element.partitionType() == Dune::InteriorEntity) - { - - // get FE function spaces to calculate gradients (gradient data of momentum balance - // equation is not stored in fluxvars since it is not evaluated at box integration point) - // copy the values of the sol vector to the localFunctionSpace values of the current element - LocalFunctionSpace localFunctionSpace(gridFunctionSpace); - localFunctionSpace.bind(element); - std::vector<Scalar> values(localFunctionSpace.size()); - for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) - { - const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); - typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; - ordering.mapIndex(di.view(),ci); - values[k] = sol[ci]; - } - - // local function space for solid displacement - typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; - const DisplacementLFS& displacementLFS =localFunctionSpace.template child<1>(); - const unsigned int dispSize = displacementLFS.child(0).size(); - typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; - // further types required for gradient calculations - typedef typename ScalarDispLFS::Traits::FiniteElementType::Traits::LocalBasisType::Traits::JacobianType JacobianType_V; - typedef typename ScalarDispLFS::Traits::FiniteElementType::Traits::LocalBasisType::Traits::RangeFieldType RF; - - unsigned int eIdx = this->problem_().model().elementMapper().index(element); - rank[eIdx] = this->gridView_().comm().rank(); - - fvGeometry.update(this->gridView_(), element); - elemVolVars.update(this->problem_(), element, fvGeometry, false); - - // loop over all local vertices of the cell - int numScv = element.subEntities(dim); - - for (int scvIdx = 0; scvIdx < numScv; ++scvIdx) - { - unsigned int vIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); - - Te[vIdxGlobal] = elemVolVars[scvIdx].temperature(); - pw[vIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx); - pn[vIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx); - pc[vIdxGlobal] = elemVolVars[scvIdx].capillaryPressure(); - sw[vIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx); - sn[vIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx); - rhoW[vIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx); - rhoN[vIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx); - // the following lines are correct for rock mechanics sign convention - // but lead to a very counter-intuitive output therefore, they are commented. - // in case of rock mechanics sign convention solid displacement is - // defined to be negative if it points in positive coordinate direction -// if(rockMechanicsSignConvention_){ -// DimVector tmpDispl; -// tmpDispl = Scalar(0); -// tmpDispl -= elemVolVars[scvIdx].displacement(); -// displacement[vIdxGlobal] = tmpDispl; -// } -// -// else - displacement[vIdxGlobal] = elemVolVars[scvIdx].displacement(); - - double Keff; - double exponent; - exponent = 22.2 * (elemVolVars[scvIdx].effPorosity - / elemVolVars[scvIdx].porosity() - 1); - Keff = this->problem_().spatialParams().intrinsicPermeability( element, fvGeometry, scvIdx)[0][0]; - Keff *= exp(exponent); - effKx[eIdx] += Keff/ numScv; - effectivePressure[eIdx] += (pn[vIdxGlobal] * sn[vIdxGlobal] - + pw[vIdxGlobal] * sw[vIdxGlobal]) - / numScv; - effPorosity[eIdx] +=elemVolVars[scvIdx].effPorosity / numScv; - }; - - const auto geometry = element.geometry(); - - const GlobalPosition& cellCenter = geometry.center(); - const GlobalPosition& cellCenterLocal = geometry.local(cellCenter); - - deltaEffPressure[eIdx] = effectivePressure[eIdx] + this->problem().pInit(cellCenter, cellCenterLocal, element); - // determin changes in effective stress from current solution - // evaluate gradient of displacement shape functions - std::vector<JacobianType_V> vRefShapeGradient(dispSize); - displacementLFS.child(0).finiteElement().localBasis().evaluateJacobian(cellCenterLocal, vRefShapeGradient); - - // get jacobian to transform the gradient to physical element - const JacobianInverseTransposed jacInvT = geometry.jacobianInverseTransposed(cellCenterLocal); - std::vector < Dune::FieldVector<RF, dim> > vShapeGradient(dispSize); - for (size_t i = 0; i < dispSize; i++) { - vShapeGradient[i] = 0.0; - jacInvT.umv(vRefShapeGradient[i][0], vShapeGradient[i]); - } - // calculate gradient of current displacement - typedef Dune::FieldMatrix<RF, dim, dim> DimMatrix; - DimMatrix uGradient(0.0); - for (int coordDir = 0; coordDir < dim; ++coordDir) { - const ScalarDispLFS & scalarDispLFS = displacementLFS.child(coordDir); - - for (size_t i = 0; i < scalarDispLFS.size(); i++) - uGradient[coordDir].axpy(values[scalarDispLFS.localIndex(i)],vShapeGradient[i]); - } - - const Dune::FieldVector<Scalar, 2> lameParams = this->problem_().spatialParams().lameParams(element,fvGeometry, 0); - const Scalar lambda = lameParams[0]; - const Scalar mu = lameParams[1]; - - // calculate strain tensor - Dune::FieldMatrix<RF, dim, dim> epsilon; - for (int i = 0; i < dim; ++i) - for (int j = 0; j < dim; ++j) - epsilon[i][j] = 0.5 * (uGradient[i][j] + uGradient[j][i]); - - RF traceEpsilon = 0; - for (int i = 0; i < dim; ++i) - traceEpsilon += epsilon[i][i]; - - // calculate effective stress tensor - Dune::FieldMatrix<RF, dim, dim> sigma(0.0); - for (int i = 0; i < dim; ++i) { - sigma[i][i] = lambda * traceEpsilon; - for (int j = 0; j < dim; ++j) - sigma[i][j] += 2.0 * mu * epsilon[i][j]; - } - - // in case of rock mechanics sign convention compressive stresses - // are defined to be positive - if(rockMechanicsSignConvention_){ - deltaEffStressX[eIdx] -= sigma[0]; - if (dim >= 2) { - deltaEffStressY[eIdx] -= sigma[1]; - } - if (dim >= 3) { - deltaEffStressZ[eIdx] -= sigma[2]; - } - } - else{ - deltaEffStressX[eIdx] = sigma[0]; - if (dim >= 2) { - deltaEffStressY[eIdx] = sigma[1]; - } - if (dim >= 3) { - deltaEffStressZ[eIdx] = sigma[2]; - } - } - - // retrieve prescribed initial stresses from problem file - DimVector tmpInitStress = this->problem_().initialStress(cellCenter, 0); - if(rockMechanicsSignConvention_){ - initStressX[eIdx][0] = tmpInitStress[0]; - if (dim >= 2) { - initStressY[eIdx][1] = tmpInitStress[1]; - } - if (dim >= 3) { - initStressZ[eIdx][2] = tmpInitStress[2]; - } - } - else{ - initStressX[eIdx][0] -= tmpInitStress[0]; - if (dim >= 2) { - initStressY[eIdx][1] -= tmpInitStress[1]; - } - if (dim >= 3) { - initStressZ[eIdx][2] -= tmpInitStress[2]; - } - } - - // calculate total stresses - // in case of rock mechanics sign convention compressive stresses - // are defined to be positive and total stress is calculated by adding the pore pressure - if(rockMechanicsSignConvention_){ - totalStressX[eIdx][0] = initStressX[eIdx][0] + deltaEffStressX[eIdx][0] + deltaEffPressure[eIdx]; - if (dim >= 2) { - totalStressX[eIdx][1] = initStressX[eIdx][1] + deltaEffStressX[eIdx][1]; - totalStressY[eIdx][0] = initStressY[eIdx][0] + deltaEffStressY[eIdx][0]; - totalStressY[eIdx][1] = initStressY[eIdx][1] + deltaEffStressY[eIdx][1] + deltaEffPressure[eIdx]; - } - if (dim >= 3) { - totalStressX[eIdx][2] = initStressX[eIdx][2] + deltaEffStressX[eIdx][2]; - totalStressY[eIdx][2] = initStressY[eIdx][2] + deltaEffStressY[eIdx][2]; - totalStressZ[eIdx][0] = initStressZ[eIdx][0] + deltaEffStressZ[eIdx][0]; - totalStressZ[eIdx][1] = initStressZ[eIdx][1] + deltaEffStressZ[eIdx][1]; - totalStressZ[eIdx][2] = initStressZ[eIdx][2] + deltaEffStressZ[eIdx][2] + deltaEffPressure[eIdx]; - } - } - else{ - totalStressX[eIdx][0] = initStressX[eIdx][0] + deltaEffStressX[eIdx][0] - deltaEffPressure[eIdx]; - if (dim >= 2) { - totalStressX[eIdx][1] = initStressX[eIdx][1] + deltaEffStressX[eIdx][1]; - totalStressY[eIdx][0] = initStressY[eIdx][0] + deltaEffStressY[eIdx][0]; - totalStressY[eIdx][1] = initStressY[eIdx][1] + deltaEffStressY[eIdx][1] - deltaEffPressure[eIdx]; - } - if (dim >= 3) { - totalStressX[eIdx][2] = initStressX[eIdx][2] + deltaEffStressX[eIdx][2]; - totalStressY[eIdx][2] = initStressY[eIdx][2] + deltaEffStressY[eIdx][2]; - totalStressZ[eIdx][0] = initStressZ[eIdx][0] + deltaEffStressZ[eIdx][0]; - totalStressZ[eIdx][1] = initStressZ[eIdx][1] + deltaEffStressZ[eIdx][1]; - totalStressZ[eIdx][2] = initStressZ[eIdx][2] + deltaEffStressZ[eIdx][2] - deltaEffPressure[eIdx]; - } - } - } - } - - // calculate principal stresses i.e. the eigenvalues of the total stress tensor - Scalar a1, a2, a3; - DimMatrix totalStress; - DimVector eigenValues; - - for (unsigned int eIdx = 0; eIdx < numElements; eIdx++) - { - eigenValues = Scalar(0); - totalStress = Scalar(0); - - totalStress[0] = totalStressX[eIdx]; - if (dim >= 2) - totalStress[1] = totalStressY[eIdx]; - if (dim >= 3) - totalStress[2] = totalStressZ[eIdx]; - - calculateEigenValues<dim>(eigenValues, totalStress); - - - for (int i = 0; i < dim; i++) - { - if (isnan(eigenValues[i])) - eigenValues[i] = 0.0; - } - - // sort principal stresses: principalStress1 >= principalStress2 >= principalStress3 - if (dim == 2) { - a1 = eigenValues[0]; - a2 = eigenValues[1]; - - if (a1 >= a2) { - principalStress1[eIdx] = a1; - principalStress2[eIdx] = a2; - } else { - principalStress1[eIdx] = a2; - principalStress2[eIdx] = a1; - } - } - - if (dim == 3) { - a1 = eigenValues[0]; - a2 = eigenValues[1]; - a3 = eigenValues[2]; - - if (a1 >= a2) { - if (a1 >= a3) { - principalStress1[eIdx] = a1; - if (a2 >= a3) { - principalStress2[eIdx] = a2; - principalStress3[eIdx] = a3; - } - else //a3 > a2 - { - principalStress2[eIdx] = a3; - principalStress3[eIdx] = a2; - } - } - else // a3 > a1 - { - principalStress1[eIdx] = a3; - principalStress2[eIdx] = a1; - principalStress3[eIdx] = a2; - } - } else // a2>a1 - { - if (a2 >= a3) { - principalStress1[eIdx] = a2; - if (a1 >= a3) { - principalStress2[eIdx] = a1; - principalStress3[eIdx] = a3; - } - else //a3>a1 - { - principalStress2[eIdx] = a3; - principalStress3[eIdx] = a1; - } - } - else //a3>a2 - { - principalStress1[eIdx] = a3; - principalStress2[eIdx] = a2; - principalStress3[eIdx] = a1; - } - } - } - Scalar taum = 0.0; - Scalar sigmam = 0.0; - Scalar Peff = effectivePressure[eIdx]; - - Scalar theta = M_PI / 6; - Scalar S0 = 0.0; - taum = (principalStress1[eIdx] - principalStress3[eIdx]) / 2; - sigmam = (principalStress1[eIdx] + principalStress3[eIdx]) / 2; - Scalar Psc = -fabs(taum) / sin(theta) + S0 * cos(theta) / sin(theta) - + sigmam; - // Pressure margins according to J. Rutqvist et al. / International Journal of Rock Mecahnics & Mining Sciences 45 (2008), 132-143 - Pcrtens[eIdx] = Peff - principalStress3[eIdx]; - Pcrshe[eIdx] = Peff - Psc; - - } - - writer.attachVertexData(Te, "T"); - writer.attachVertexData(pw, "pW"); - writer.attachVertexData(pn, "pN"); - writer.attachVertexData(pc, "pC"); - writer.attachVertexData(sw, "SW"); - writer.attachVertexData(sn, "SN"); - writer.attachVertexData(rhoW, "rhoW"); - writer.attachVertexData(rhoN, "rhoN"); - writer.attachVertexData(displacement, "u", dim); - - writer.attachCellData(deltaEffStressX, "effective stress changes X", dim); - if (dim >= 2) - writer.attachCellData(deltaEffStressY, "effective stress changes Y", dim); - if (dim >= 3) - writer.attachCellData(deltaEffStressZ, "effective stress changes Z", dim); - - writer.attachCellData(principalStress1, "principal stress 1"); - if (dim >= 2) - writer.attachCellData(principalStress2, "principal stress 2"); - if (dim >= 3) - writer.attachCellData(principalStress3, "principal stress 3"); - - writer.attachCellData(totalStressX, "total stresses X", dim); - if (dim >= 2) - writer.attachCellData(totalStressY, "total stresses Y", dim); - if (dim >= 3) - writer.attachCellData(totalStressZ, "total stresses Z", dim); - - writer.attachCellData(initStressX, "initial stresses X", dim); - if (dim >= 2) - writer.attachCellData(initStressY, "initial stresses Y", dim); - if (dim >= 3) - writer.attachCellData(initStressZ, "initial stresses Z", dim); - - writer.attachCellData(deltaEffPressure, "delta pEff"); - writer.attachCellData(effectivePressure, "effectivePressure"); - writer.attachCellData(Pcrtens, "Pcr_tensile"); - writer.attachCellData(Pcrshe, "Pcr_shear"); - writer.attachCellData(effKx, "effective Kxx"); - writer.attachCellData(effPorosity, "effective Porosity"); - - - } - - /*! - * \brief Applies the initial solution for all vertices of the grid. - */ - void applyInitialSolution_() { - typedef typename GET_PROP_TYPE(TypeTag, InitialPressSat) InitialPressSat; - InitialPressSat initialPressSat(this->problem_().gridView()); - std::cout << "el2pmodel calls: initialPressSat" << std::endl; - initialPressSat.setPressure(this->problem_().pInit()); - - typedef typename GET_PROP_TYPE(TypeTag, InitialDisplacement) InitialDisplacement; - InitialDisplacement initialDisplacement(this->problem_().gridView()); - - typedef Dune::PDELab::CompositeGridFunction<InitialPressSat, - InitialDisplacement> InitialSolution; - InitialSolution initialSolution(initialPressSat, initialDisplacement); - - int numDofs = this->jacobianAssembler().gridFunctionSpace().size(); - //this->curSol().resize(numDofs); - //this->prevSol().resize(numDofs); - std::cout << "numDofs = " << numDofs << std::endl; - - Dune::PDELab::interpolate(initialSolution, - this->jacobianAssembler().gridFunctionSpace(), this->curSol()); - Dune::PDELab::interpolate(initialSolution, - this->jacobianAssembler().gridFunctionSpace(), this->prevSol()); - } - - const Problem& problem() const { - return this->problem_(); - } - -private: - bool rockMechanicsSignConvention_; - -}; -} -#include "el2ppropertydefaults.hh" #endif diff --git a/dumux/geomechanics/el2p/el2pnewtoncontroller.hh b/dumux/geomechanics/el2p/el2pnewtoncontroller.hh index 9787b1a8aed73b549baf2b40c5ff364db82721cd..debec503983ff439cc5e8562e15dbf395534f84b 100644 --- a/dumux/geomechanics/el2p/el2pnewtoncontroller.hh +++ b/dumux/geomechanics/el2p/el2pnewtoncontroller.hh @@ -1,170 +1,8 @@ -// -*- 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 An el2p specific controller for the newton solver. - * - * This controller 'knows' what a 'physically meaningful' solution is - * which allows the newton method to abort quicker if the solution is - * way out of bounds. - */ -#ifndef DUMUX_EL2P_NEWTON_CONTROLLER_HH -#define DUMUX_EL2P_NEWTON_CONTROLLER_HH +#ifndef DUMUX_EL2P_NEWTON_CONTROLLER_HH_OLD +#define DUMUX_EL2P_NEWTON_CONTROLLER_HH_OLD -#include <dumux/nonlinear/newtoncontroller.hh> +#warning this header is deprecated, use dumux/geomechanics/el2p/newtoncontroller.hh instead -namespace Dumux { - -template <class TypeTag> -class ElTwoPNewtonController : public NewtonController<TypeTag> -{ - typedef NewtonController<TypeTag> ParentType; - - typedef typename GET_PROP_TYPE(TypeTag, NewtonController) Implementation; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod; - - typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, LinearSolver) LinearSolver; - -public: - /*! - * \brief Destructor - */ - ElTwoPNewtonController(const Problem &problem) - : ParentType(problem),linearSolver_(problem) - { - this->setTargetSteps(9); - this->setMaxSteps(18); - }; - - void newtonUpdateRelError(const SolutionVector &uOld, - const SolutionVector &deltaU) - { - // calculate the relative error as the maximum relative - // deflection in any degree of freedom. - this->shift_ = 0; - - for (int i = 0; i < int(uOld.base().size()); ++i) { - Scalar vertErr = std::abs(deltaU.base()[i]/(1.0 + std::abs((uOld.base()[i]) + uOld.base()[i] - deltaU.base()[i])/2)); - this->shift_ = std::max(this->shift_, vertErr); - } - - this->shift_ = this->gridView_().comm().max(this->shift_); - } - - void newtonUpdate(SolutionVector &uCurrentIter, - const SolutionVector &uLastIter, - const SolutionVector &deltaU) - { -// this->writeConvergence_(uLastIter, deltaU); - - newtonUpdateRelError(uLastIter, deltaU); - - uCurrentIter = uLastIter; - uCurrentIter -= deltaU; - -// printvector(std::cout, deltaU, "new solution", "row", 12, 1, 3); - } - - /*! - * \brief Solve the linear system of equations \f$\mathbf{A}x - b = 0\f$. - * - * Throws Dumux::NumericalProblem if the linear solver didn't - * converge. - * - * \param A The matrix of the linear system of equations - * \param x The vector which solves the linear system - * \param b The right hand side of the linear system - */ - void newtonSolveLinear(JacobianMatrix &A, - SolutionVector &x, - SolutionVector &b) - { - try { - if (this->numSteps_ == 0) - { - Scalar norm2 = b.base().two_norm2(); - if (this->gridView_().comm().size() > 1) - norm2 = this->gridView_().comm().sum(norm2); - - initialAbsoluteError_ = std::sqrt(norm2); - lastAbsoluteError_ = initialAbsoluteError_; - } - - int converged = linearSolver_.solve(A.base(), x.base(), b.base()); -// printvector(std::cout, x.base(), "x", "row", 5, 1, 5); -// printvector(std::cout, b.base(), "rhs", "row", 5, 1, 5); -// Dune::writeMatrixToMatlab(A.base(), "matrix.txt"); - - // make sure all processes converged - int convergedRemote = converged; - if (this->gridView_().comm().size() > 1) - convergedRemote = this->gridView_().comm().min(converged); - - if (!converged) { - DUNE_THROW(NumericalProblem, - "Linear solver did not converge"); - } - else if (!convergedRemote) { - DUNE_THROW(NumericalProblem, - "Linear solver did not converge on a remote process"); - } - } - catch (Dune::MatrixBlockError e) { - // make sure all processes converged - int converged = 0; - if (this->gridView_().comm().size() > 1) - converged = this->gridView_().comm().min(converged); - - Dumux::NumericalProblem p; - std::string msg; - std::ostringstream ms(msg); - ms << e.what() << "M=" << A.base()[e.r][e.c]; - p.message(ms.str()); - throw p; - } - catch (const Dune::Exception &e) { - // make sure all processes converged - int converged = 0; - if (this->gridView_().comm().size() > 1) - converged = this->gridView_().comm().min(converged); - - Dumux::NumericalProblem p; - p.message(e.what()); - throw p; - } - } - - // absolute errors and tolerance - Scalar absoluteError_; - Scalar lastAbsoluteError_; - Scalar initialAbsoluteError_; - Scalar absoluteTolerance_; - - // the linear solver - LinearSolver linearSolver_; - -}; -} +#include <dumux/geomechanics/el2p/newtoncontroller.hh> #endif diff --git a/dumux/geomechanics/el2p/el2pproperties.hh b/dumux/geomechanics/el2p/el2pproperties.hh index 03a32fb68574b1aa074218ce7b693f1d1c1d056d..615f3fe5dda4295f73ed6cbff84e0da7f1523bd8 100644 --- a/dumux/geomechanics/el2p/el2pproperties.hh +++ b/dumux/geomechanics/el2p/el2pproperties.hh @@ -1,90 +1,8 @@ -// -*- 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 Defines the properties required for the two phase linear-elastic model. - * - * This class inherits from the properties of the two-phase model and - * from the properties of the simple linear-elastic model - */ +#ifndef DUMUX_ELASTIC2P_PROPERTIES_HH_OLD +#define DUMUX_ELASTIC2P_PROPERTIES_HH_OLD -#ifndef DUMUX_ELASTIC2P_PROPERTIES_HH -#define DUMUX_ELASTIC2P_PROPERTIES_HH +#warning this header is deprecated, use dumux/geomechanics/el2p/properties.hh instead -#include <dumux/implicit/box/properties.hh> -#include <dumux/porousmediumflow/2p/implicit/properties.hh> - -namespace Dumux -{ -//////////////////////////////// -// properties -//////////////////////////////// -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tag for the twophase model with a linear elastic matrix -NEW_TYPE_TAG(BoxElasticTwoP, INHERITS_FROM(BoxModel)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// -NEW_PROP_TAG(DisplacementGridFunctionSpace); //!< grid function space for the displacement -NEW_PROP_TAG(PressureGridFunctionSpace); //!< grid function space for the pressure, saturation, ... -NEW_PROP_TAG(GridOperatorSpace); //!< The grid operator space -NEW_PROP_TAG(GridOperator); //!< The grid operator space -NEW_PROP_TAG(PressureFEM); //!< FE space used for pressure, saturation, ... -NEW_PROP_TAG(DisplacementFEM); //!< FE space used for displacement - -//! Returns whether the output should be written according to -//! rock mechanics sign convention (compressive stresses > 0) -NEW_PROP_TAG(VtkRockMechanicsSignConvention); - -//! Specifies the grid function space used for sub-problems -NEW_PROP_TAG(GridFunctionSpace); - -//! Specifies the grid operator used for sub-problems -NEW_PROP_TAG(GridOperator); - -//! Specifies the grid operator space used for sub-problems -NEW_PROP_TAG(GridOperatorSpace); - -//! Specifies the type of the constraints -NEW_PROP_TAG(Constraints); - -//! Specifies the type of the constraints transformation -NEW_PROP_TAG(ConstraintsTrafo); - -//! Specifies the local finite element space -NEW_PROP_TAG(LocalFEMSpace); - -//! Specifies the local operator -NEW_PROP_TAG(LocalOperator); - -//! The type traits required for using the AMG backend -NEW_PROP_TAG(AmgTraits); -} - -} +#include <dumux/geomechanics/el2p/properties.hh> #endif - diff --git a/dumux/geomechanics/el2p/el2ppropertydefaults.hh b/dumux/geomechanics/el2p/el2ppropertydefaults.hh index 9e3a33d75462fd3ca25e6c67a58ba4ef949da37f..a2470dbc649ce31fe01d90112562bff36f179546 100644 --- a/dumux/geomechanics/el2p/el2ppropertydefaults.hh +++ b/dumux/geomechanics/el2p/el2ppropertydefaults.hh @@ -1,433 +1,8 @@ -// -*- 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 Defines the properties required for the two phase linear-elastic model. - * - * This class inherits from the properties of the two-phase model and - * from the properties of the simple linear-elastic model - */ +#ifndef DUMUX_ELASTIC2P_PROPERTY_DEFAULTS_HH_OLD +#define DUMUX_ELASTIC2P_PROPERTY_DEFAULTS_HH_OLD -#ifndef DUMUX_ELASTIC2P_PROPERTY_DEFAULTS_HH -#define DUMUX_ELASTIC2P_PROPERTY_DEFAULTS_HH +#warning this header is deprecated, use dumux/geomechanics/el2p/propertydefaults.hh instead -#include <dune/istl/schwarz.hh> -#include <dune/istl/novlpschwarz.hh> -#include <dune/istl/owneroverlapcopy.hh> -#include <dune/istl/paamg/pinfo.hh> -#include <dune/istl/preconditioners.hh> - -#include <dune/pdelab/backend/istlmatrixbackend.hh> -#include <dune/pdelab/gridfunctionspace/gridfunctionspace.hh> -#include <dune/pdelab/backend/istlvectorbackend.hh> -#include <dune/pdelab/common/function.hh> -#include <dune/pdelab/gridoperator/gridoperator.hh> -#include <dune/pdelab/finiteelementmap/qkfem.hh> - -#include "el2pproperties.hh" - -#include "el2pmodel.hh" -#include "el2pbasemodel.hh" -#include "el2pindices.hh" -#include "el2plocalresidual.hh" -#include "el2plocaljacobian.hh" -#include "el2pfluxvariables.hh" -#include "el2pelementvolumevariables.hh" -#include "el2pvolumevariables.hh" -#include "el2plocaloperator.hh" -#include "el2passembler.hh" -#include "el2pnewtoncontroller.hh" -#include "el2pindices.hh" -#include <dumux/implicit/box/propertydefaults.hh> -#include <dumux/porousmediumflow/2p/implicit/propertydefaults.hh> -#include <dumux/linear/seqsolverbackend.hh> -#include <dumux/linear/amgbackend.hh> - -namespace Dumux -{ - -////////////////////////////////////////////////////////////////// -// Property defaults -////////////////////////////////////////////////////////////////// - -namespace Properties -{ -SET_PROP(BoxElasticTwoP, NumEq) //!< set the number of equations to dim + 2 -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; - static const int dim = Grid::dimension; -public: - static const int value = dim + 2; -}; - -SET_INT_PROP(BoxElasticTwoP, NumPhases, 2); //!< The number of fluid phases in the elastic 2p model is 2 - -//! Use the elastic local jacobian operator for the two-phase linear-elastic model -SET_TYPE_PROP(BoxElasticTwoP, - LocalResidual, - ElTwoPLocalResidual<TypeTag>); - -//! the Model property -SET_TYPE_PROP(BoxElasticTwoP, Model, ElTwoPModel<TypeTag>); - -/*! - * \brief An array of secondary variable containers. - */ -SET_TYPE_PROP(BoxElasticTwoP, ElementVolumeVariables, Dumux::ElTwoPElementVolumeVariables<TypeTag>); - -//! the VolumeVariables property -SET_TYPE_PROP(BoxElasticTwoP, VolumeVariables, ElTwoPVolumeVariables<TypeTag>); - -//! Set the default formulation to pWsN -SET_INT_PROP(BoxElasticTwoP, - Formulation, - 0); - -//! The indices required by the two-phase linear-elastic model - -SET_PROP(BoxElasticTwoP, Indices) -{ - typedef ElTwoPIndices<TypeTag> type; -}; - -//! The FluxVariables required by the two-phase linear-elastic model -SET_TYPE_PROP(BoxElasticTwoP, FluxVariables, ElTwoPFluxVariables<TypeTag>); - -//! the default upwind factor. Default 1.0, i.e. fully upwind... -SET_SCALAR_PROP(BoxElasticTwoP, ImplicitMassUpwindWeight, 1.0); - -//! weight for the upwind mobility in the velocity calculation -SET_SCALAR_PROP(BoxElasticTwoP, ImplicitMobilityUpwindWeight, 1.0); - -//! enable gravity by default -SET_BOOL_PROP(BoxElasticTwoP, ProblemEnableGravity, true); - - -//! Enable evaluation of shape function gradients at the sub-control volume center by default -// Used for the computation of the pressure gradients -SET_BOOL_PROP(BoxElasticTwoP, EvalGradientsAtSCVCenter, true); - -/*! - * \brief Set the property for the material parameters by extracting - * it from the material law. - */ -SET_PROP(BoxElasticTwoP, MaterialLawParams) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - -public: - typedef typename MaterialLaw::Params type; -}; - - -// use the SuperLU linear solver by default -#if HAVE_SUPERLU -SET_TYPE_PROP(BoxElasticTwoP, LinearSolver, Dumux::SuperLUBackend<TypeTag> ); -#else -#warning no SuperLU detected, defaulting to ILU0BiCGSTAB. For many problems, the el2p model requires a direct solver. -SET_TYPE_PROP(BoxElasticTwoP, LinearSolver, Dumux::ILU0BiCGSTABBackend<TypeTag> ); -#endif - -// set the grid operator -SET_PROP(BoxElasticTwoP, GridOperator) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, ConstraintsTrafo) ConstraintsTrafo; - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; - typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LocalOperator; - typedef typename Dune::PDELab::ISTLMatrixBackend MatrixBackend; - - enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; - -public: - - typedef Dune::PDELab::GridOperator<GridFunctionSpace, - GridFunctionSpace, - LocalOperator, - MatrixBackend, - Scalar, Scalar, Scalar, - ConstraintsTrafo, - ConstraintsTrafo, - true - > type; -}; - -SET_PROP(BoxElasticTwoP, JacobianMatrix) -{ -private: - //typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GFSU; - typedef typename GFSU::template ConstraintsContainer<Scalar>::Type CU; - //! The global assembler type - typedef Dune::PDELab::DefaultAssembler<GFSU,GFSU,CU,CU,true> Assembler; - - //! The type of the domain (solution). - typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Domain; - //! The type of the range (residual). - typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Range; - //! The type of the jacobian. - typedef typename Dune::PDELab::ISTLMatrixBackend MB; - typedef typename Dune::PDELab::BackendMatrixSelector<MB,Domain,Range,Scalar>::Type Jacobian; - - //! The local assembler type - typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LOP; - typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; - typedef Dune::PDELab::DefaultLocalAssembler<GridOperator,LOP,true> - LocalAssembler; - //! The grid operator traits - typedef Dune::PDELab::GridOperatorTraits - <GFSU,GFSU,MB,Scalar,Scalar,Scalar,CU,CU,Assembler,LocalAssembler> Traits; -public: - typedef typename Traits::Jacobian type; -}; - -SET_PROP(BoxElasticTwoP, SolutionVector) -{ -private: - //typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GFSU; - typedef typename GFSU::template ConstraintsContainer<Scalar>::Type CU; - //! The global assembler type - typedef Dune::PDELab::DefaultAssembler<GFSU,GFSU,CU,CU,true> Assembler; - - //! The type of the domain (solution). - typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Domain; - //! The type of the range (residual). - typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Range; - //! The type of the jacobian. - typedef typename Dune::PDELab::ISTLMatrixBackend MB; - typedef typename Dune::PDELab::BackendMatrixSelector<MB,Domain,Range,Scalar>::Type Jacobian; - - //! The local assembler type - typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LOP; - typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; - typedef Dune::PDELab::DefaultLocalAssembler<GridOperator,LOP,true> - LocalAssembler; - //! The grid operator traits - typedef Dune::PDELab::GridOperatorTraits - <GFSU,GFSU,MB,Scalar,Scalar,Scalar,CU,CU,Assembler,LocalAssembler> Traits; -public: - typedef typename Traits::Domain type; -}; - -SET_PROP(BoxElasticTwoP, PressureGridFunctionSpace) -{private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, PressureFEM) FEM; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename Dune::PDELab::EntityBlockedOrderingTag OrderingTag; - typedef typename Dune::PDELab::ISTLVectorBackend<> VBE; - enum{numEq = GET_PROP_VALUE(TypeTag, NumEq), - dim = GridView::dimension}; -public: - typedef Dune::PDELab::NoConstraints Constraints; - - typedef Dune::PDELab::GridFunctionSpace<GridView, FEM, Constraints, VBE> - ScalarGridFunctionSpace; - - typedef Dune::PDELab::PowerGridFunctionSpace<ScalarGridFunctionSpace, numEq-dim, VBE, OrderingTag> - type; - - typedef typename type::template ConstraintsContainer<Scalar>::Type - ConstraintsTrafo; -}; - -SET_PROP(BoxElasticTwoP, DisplacementGridFunctionSpace) -{private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, DisplacementFEM) FEM; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename Dune::PDELab::EntityBlockedOrderingTag OrderingTag; - typedef typename Dune::PDELab::ISTLVectorBackend<> VBE; - enum{dim = GridView::dimension}; -public: - typedef Dune::PDELab::NoConstraints Constraints; - - typedef Dune::PDELab::GridFunctionSpace<GridView, FEM, Constraints, VBE> - ScalarGridFunctionSpace; - - typedef Dune::PDELab::PowerGridFunctionSpace<ScalarGridFunctionSpace, dim, VBE, OrderingTag> - type; - - typedef typename type::template ConstraintsContainer<Scalar>::Type - ConstraintsTrafo; -}; - -SET_PROP(BoxElasticTwoP, GridFunctionSpace) -{private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, PressureGridFunctionSpace) PressureGFS; - typedef typename GET_PROP_TYPE(TypeTag, DisplacementGridFunctionSpace) DisplacementGFS; - typedef typename Dune::PDELab::LexicographicOrderingTag OrderingTag; - typedef typename Dune::PDELab::ISTLVectorBackend<> VBE; -public: - typedef Dune::PDELab::NoConstraints Constraints; - - typedef void ScalarGridFunctionSpace; - - typedef Dune::PDELab::CompositeGridFunctionSpace<VBE, OrderingTag, PressureGFS, DisplacementGFS> type; - - typedef typename type::template ConstraintsContainer<Scalar>::Type - ConstraintsTrafo; -}; - -SET_PROP(BoxElasticTwoP, ConstraintsTrafo) -{private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; -public: - typedef typename GridFunctionSpace::template ConstraintsContainer<Scalar>::Type type; -}; - -// set the grid function space for the sub-models -SET_TYPE_PROP(BoxElasticTwoP, Constraints, Dune::PDELab::NoConstraints); - -SET_TYPE_PROP(BoxElasticTwoP, JacobianAssembler, Dumux::PDELab::El2PAssembler<TypeTag>); - -SET_PROP(BoxElasticTwoP, WettingPhase) -{ private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; -public: - typedef Dumux::LiquidPhase<Scalar, Dumux::NullComponent<Scalar> > type; -}; - -SET_PROP(BoxElasticTwoP, NonwettingPhase) -{ private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; -public: - typedef Dumux::LiquidPhase<Scalar, Dumux::NullComponent<Scalar> > type; -}; - -SET_PROP(BoxElasticTwoP, FluidSystem) -{ private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, WettingPhase) WettingPhase; - typedef typename GET_PROP_TYPE(TypeTag, NonwettingPhase) NonwettingPhase; - -public: - typedef Dumux::FluidSystems::TwoPImmiscible<Scalar, - WettingPhase, - NonwettingPhase> type; -}; - -SET_PROP(BoxElasticTwoP, FluidState) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; -public: - typedef ImmiscibleFluidState<Scalar, FluidSystem> type; -}; - -// enable jacobian matrix recycling by default -SET_BOOL_PROP(BoxElasticTwoP, ImplicitEnableJacobianRecycling, false); -// enable partial reassembling by default -SET_BOOL_PROP(BoxElasticTwoP, ImplicitEnablePartialReassemble, false); - -SET_TYPE_PROP(BoxElasticTwoP, NewtonController, ElTwoPNewtonController<TypeTag>); - -SET_PROP(BoxElasticTwoP, LocalOperator) -{ - typedef Dumux::PDELab::El2PLocalOperator<TypeTag> type; -}; - -//! use the local FEM space associated with cubes by default -SET_PROP(BoxElasticTwoP, LocalFEMSpace) -{ - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - -public: - typedef Dune::PDELab::QkLocalFiniteElementMap<GridView,Scalar,Scalar,1> type; -}; - -/*! - * \brief A vector of primary variables. - */ -SET_PROP(BoxElasticTwoP, PrimaryVariables) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; -public: - typedef Dune::FieldVector<Scalar, numEq> type; -}; - -template <class TypeTag, class MType, class VType, bool isParallel> -class ElasticTwoPSolverTraits -: public NonoverlappingSolverTraits<MType, VType, isParallel> -{ -public: - typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; -}; - -template <class TypeTag, class MType, class VType> -class ElasticTwoPSolverTraits<TypeTag, MType, VType, true> -: public NonoverlappingSolverTraits<MType, VType, true> -{ -public: - typedef MType JacobianMatrix; -}; - -//! define the traits for the AMGBackend -SET_PROP(BoxElasticTwoP, AmgTraits) -{ -public: - typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - enum { dofCodim = Grid::dimension, - isNonOverlapping = true }; - enum { isParallel = Dune::Capabilities::canCommunicate<Grid, dofCodim>::v }; - - static const int numEq = isParallel ? GET_PROP_VALUE(TypeTag, NumEq) - : GET_PROP_TYPE(TypeTag, JacobianMatrix)::block_type::rows; - - typedef Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,numEq,numEq> > MType; - typedef Dune::BlockVector<Dune::FieldVector<Scalar,numEq> > VType; - typedef ElasticTwoPSolverTraits<TypeTag, MType, VType, isParallel> SolverTraits; - typedef typename SolverTraits::Comm Comm; - typedef typename SolverTraits::LinearOperator LinearOperator; - typedef typename SolverTraits::ScalarProduct ScalarProduct; - typedef typename SolverTraits::Smoother Smoother; - typedef typename SolverTraits::JacobianMatrix JacobianMatrix; -}; - -//! The local jacobian operator -SET_TYPE_PROP(BoxElasticTwoP, LocalJacobian, Dumux::ElTwoPLocalJacobian<TypeTag>); - -SET_TYPE_PROP(BoxElasticTwoP, BaseModel, ElTwoPBaseModel<TypeTag>); - -//! set number of equations of the mathematical model as default -SET_INT_PROP(BoxElasticTwoP, LinearSolverBlockSize, 1); - -// write the stress and displacement output according to rock mechanics sign convention (compressive stresses > 0) -SET_BOOL_PROP(BoxElasticTwoP, VtkRockMechanicsSignConvention, true); - -// \} -} -} +#include <dumux/geomechanics/el2p/propertydefaults.hh> #endif - diff --git a/dumux/geomechanics/el2p/el2pvolumevariables.hh b/dumux/geomechanics/el2p/el2pvolumevariables.hh index e64f9aba5733bc68112b72ef8ef22efe0f3f77e7..75c66590c5fff40eb734bad13e023f91f9bd6f16 100644 --- a/dumux/geomechanics/el2p/el2pvolumevariables.hh +++ b/dumux/geomechanics/el2p/el2pvolumevariables.hh @@ -1,174 +1,8 @@ -// -*- 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 Quantities required by the two-phase linear-elastic model which - * are defined on a vertex. - */ -#ifndef DUMUX_ELASTIC2P_VOLUME_VARIABLES_HH -#define DUMUX_ELASTIC2P_VOLUME_VARIABLES_HH +#ifndef DUMUX_ELASTIC2P_VOLUME_VARIABLES_HH_OLD +#define DUMUX_ELASTIC2P_VOLUME_VARIABLES_HH_OLD -#include <dumux/porousmediumflow/2p/implicit/volumevariables.hh> +#warning this header is deprecated, use dumux/geomechanics/el2p/volumevariables.hh instead -#include "el2pproperties.hh" - -namespace Dumux { -/*! - * \ingroup ElTwoPModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are are constant within a - * finite volume in the two-phase linear-elastic model. - * - * This class inherits from the vertexdata of the two-phase - * model and from the vertexdata of the simple - * linear-elastic model - */ -template<class TypeTag> -class ElTwoPVolumeVariables: public TwoPVolumeVariables<TypeTag> { - - typedef TwoPVolumeVariables<TypeTag> TwoPBase; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum { - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - - enum { dim = GridView::dimension }; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dim> DimVector; - -public: - /*! - * \copydoc ImplicitVolumeVariables::update - */ - void update(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int scvIdx, - bool isOldSol) - { - TwoPBase::update(priVars, problem, element, fvGeometry, scvIdx, isOldSol); - primaryVars_ = priVars; - - for (int coordDir = 0; coordDir < dim; ++coordDir) - displacement_[coordDir] = priVars[Indices::u(coordDir)]; - - effFluidDensity_ = this->density(wPhaseIdx) * this->saturation(wPhaseIdx) - + this->density(nPhaseIdx) * this->saturation(nPhaseIdx); - - const Dune::FieldVector<Scalar, 2> &lameParams = - problem.spatialParams().lameParams(element, fvGeometry, scvIdx); - - lambda_ = lameParams[0]; - mu_ = lameParams[1]; - - rockDensity_ = problem.spatialParams().rockDensity(element, scvIdx); - } - - /*! - * \brief Return the vector of primary variables - */ - const PrimaryVariables &primaryVars() const - { return primaryVars_; } - - /*! - * \brief Return the vector of primary variables - */ - const Scalar &priVar(int idx) const - { return primaryVars_[idx]; } - - /*! - * \brief Sets the evaluation point used in the by the local jacobian. - */ - void setEvalPoint(const Implementation *ep) - { } - - /*! - * \brief Returns the effective effective fluid density within - * the control volume. - */ - Scalar effFluidDensity() const - { return effFluidDensity_; } - - - /*! - * \brief Returns the Lame parameter lambda within the control volume. - */ - Scalar lambda() const - { return lambda_; } - - /*! - * \brief Returns the Lame parameter mu within the control volume. - */ - Scalar mu() const - { return mu_; } - - /*! - * \brief Returns the rock density within the control volume. - */ - Scalar rockDensity() const - { return rockDensity_; } - - /*! - * \brief Returns the solid displacement in all space - * directions within the control volume. - */ - Scalar displacement(int dimIdx) const - { return displacement_[dimIdx]; } - - /*! - * \brief Returns the solid displacement vector - * within the control volume. - */ - DimVector displacement() const - { return displacement_; } - - mutable Scalar divU; - mutable Scalar effPorosity; - -protected: - Scalar effFluidDensity_; - PrimaryVariables primaryVars_, prevPrimaryVars_; - DimVector displacement_, prevDisplacement_; - Scalar lambda_; - Scalar mu_; - Scalar rockDensity_; - -private: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } -}; - -} +#include <dumux/geomechanics/el2p/volumevariables.hh> #endif diff --git a/dumux/geomechanics/el2p/elementvolumevariables.hh b/dumux/geomechanics/el2p/elementvolumevariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..0b2f3690023a15b469358f594e55dbc32aeae797 --- /dev/null +++ b/dumux/geomechanics/el2p/elementvolumevariables.hh @@ -0,0 +1,303 @@ +// -*- 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 Volume variables gathered on an element + */ +#ifndef DUMUX_BOX_EL2P_ELEMENT_VOLUME_VARIABLES_HH +#define DUMUX_BOX_EL2P_ELEMENT_VOLUME_VARIABLES_HH + +#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> + +#include <dumux/implicit/box/elementvolumevariables.hh> +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup ElTwoPBoxModel + * + * \brief This class stores an array of VolumeVariables objects, one + * volume variables object for each of the element's vertices + */ +template<class TypeTag> +class ElTwoPElementVolumeVariables : public std::vector<typename GET_PROP_TYPE(TypeTag, VolumeVariables) > +{ + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename Element::Geometry::JacobianInverseTransposed JacobianInverseTransposed; + + enum { dim = GridView::dimension }; + enum { dimWorld = GridView::dimensionworld }; + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; + + typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx + }; + +public: + /*! + * \brief The constructor. + */ + ElTwoPElementVolumeVariables() + { } + + /*! + * \brief Construct the volume variables for all vertices of an element. + * + * \param problem The problem which needs to be simulated. + * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated + * \param fvGeometry The finite volume geometry of the element + * \param isOldSol Tells whether the model's previous or current solution should be used. + * + * This class is required for the update of the effective porosity values at the + * vertices since it is a function of the divergence of the solid displacement + * at the integration points + */ + void update(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + bool isOldSol) + { + // retrieve the current or the previous solution vector and write the values into globalSol + const SolutionVector &globalSol = + isOldSol? + problem.model().prevSol(): + problem.model().curSol(); + + const GridFunctionSpace& gridFunctionSpace = problem.model().jacobianAssembler().gridFunctionSpace(); + const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); + // copy the values of the globalSol vector to the localFunctionSpace values of the current element + LocalFunctionSpace localFunctionSpace(gridFunctionSpace); + localFunctionSpace.bind(element); + std::vector<Scalar> values(localFunctionSpace.size()); + for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) + { + const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); + typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; + ordering.mapIndex(di.view(),ci); + values[k] = globalSol[ci]; + } + + // pressure and saturation local function space (mass balance equations) + typedef typename LocalFunctionSpace::template Child<0>::Type PressSatLFS; + const PressSatLFS& pressSatLFS = localFunctionSpace.template child<0>(); + // local function space for pressure + typedef typename PressSatLFS::template Child<0>::Type PressLFS; + const PressLFS& pressLFS = pressSatLFS.template child<0>(); + // local function space for saturation + typedef typename PressSatLFS::template Child<1>::Type SatLFS; + const SatLFS& satLFS = pressSatLFS.template child<1>(); + // local function space for solid displacement + typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; + const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); + typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; + + int numScv = element.subEntities(dim); + this->resize(numScv); + + for (int scvIdx = 0; scvIdx < numScv; scvIdx++) + { + // solution vector solI for each vertex + PrimaryVariables solI; + // pressure and saturation values + solI[pressureIdx] = values[pressLFS.localIndex(scvIdx)]; + solI[saturationIdx] = values[satLFS.localIndex(scvIdx)]; + // solid displacement values for each coordinate direction + for (int coordDir = 0; coordDir < dim; coordDir++) + { + const ScalarDispLFS& scalarDispLFS = displacementLFS.child(coordDir); + solI[Indices::u(coordDir)] = values[scalarDispLFS.localIndex(scvIdx)]; + } + // reset evaluation point to zero + (*this)[scvIdx].setEvalPoint(0); + + (*this)[scvIdx].update(solI, + problem, + element, + fvGeometry, + scvIdx, + isOldSol); + + Valgrind::CheckDefined((*this)[scvIdx]); + } + this->updateEffPorosity(problem, element, fvGeometry, isOldSol); + + if (isOldSol) + prevValues_ = values; + else + dofValues_ = values; + } + + /*! + * \brief Update the effective porosities for all vertices of an element. + * + * \param problem The problem which needs to be simulated. + * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated + * \param fvGeometry The finite volume geometry of the element + * \param isOldSol Specifies whether this is the previous solution or the current one + * + * This function is required for the update of the effective porosity values at the + * vertices. + * + * During the partial derivative calculation, changes of the solid displacement + * at vertex i can affect effective porosities of all element vertices. + * To correctly update the effective porosities of all element vertices + * an iteration over all scv faces is required. + * The remaining volvars are only updated for the vertex whose primary variable + * is changed for the derivative calculation. + */ + void updateEffPorosity(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + bool isOldSol) + { + int numScv = element.subEntities(dim); + + // retrieve the current or the previous solution vector and write the values into globalSol + const SolutionVector &globalSol = + isOldSol? + problem.model().prevSol(): + problem.model().curSol(); + + // copy the values of the globalSol vector to the localFunctionSpace values of the current element + const GridFunctionSpace& gridFunctionSpace = problem.model().jacobianAssembler().gridFunctionSpace(); + const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); + LocalFunctionSpace localFunctionSpace(gridFunctionSpace); + localFunctionSpace.bind(element); + std::vector<Scalar> values(localFunctionSpace.size()); + for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) + { + const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); + typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; + ordering.mapIndex(di.view(),ci); + values[k] = globalSol[ci]; + } + + // local function space for solid displacement + typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; + const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); + const unsigned int dispSize = displacementLFS.child(0).size(); + typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; + // further types required for gradient calculations + typedef typename ScalarDispLFS::Traits::FiniteElementType:: + Traits::LocalBasisType::Traits::JacobianType JacobianType_V; + typedef typename ScalarDispLFS::Traits::FiniteElementType:: + Traits::LocalBasisType::Traits::RangeFieldType RF; + typedef Dune::FieldMatrix<RF, dim, dim> Tensor; + + for (int scvIdx = 0; scvIdx < numScv; scvIdx++) + (*this)[scvIdx].effPorosity = 0.0; + + for (int scvIdx = 0; scvIdx < numScv; scvIdx++) + { + GlobalPosition scvCenter = fvGeometry.subContVol[scvIdx].localCenter; + + // evaluate gradient of displacement shape functions at the center of + // the sub control volume in the reference element + std::vector<JacobianType_V> vRefShapeGradient(dispSize); + displacementLFS.child(0).finiteElement().localBasis().evaluateJacobian(scvCenter, vRefShapeGradient); + + // transform gradient to element in global coordinates + const JacobianInverseTransposed jacInvT = element.geometry().jacobianInverseTransposed(scvCenter); + std::vector<Dune::FieldVector<RF,dim> > vShapeGradient(dispSize); + + // loop over element vertices + for (size_t i = 0; i < dispSize; i++) + { + vShapeGradient[i] = 0.0; + jacInvT.umv(vRefShapeGradient[i][0],vShapeGradient[i]); + } + + // calculate gradient of current displacement + // (gradient of a vector is a tensor) + Tensor uGradient(0.0); + // loop over coordinate directions + for(int coordDir = 0; coordDir < dim; ++coordDir) + { + const ScalarDispLFS & scalarDispLFS = displacementLFS.child(coordDir); + // loop over element vertices + for (size_t i = 0; i < scalarDispLFS.size(); i++) + uGradient[coordDir].axpy((*this)[i].displacement(coordDir), vShapeGradient[i]); + } + + // calculate the divergence of u + (*this)[scvIdx].divU = 0.0; + + for (int coordDir = 0; coordDir < dim; coordDir++) + (*this)[scvIdx].divU += uGradient[coordDir][coordDir]; + + // calculate the effective porosity + if(problem.coupled() == true) + { + if ((*this)[scvIdx].divU < -(*this)[scvIdx].porosity()) + { + (*this)[scvIdx].effPorosity = (*this)[scvIdx].porosity(); + std::cout<<"volume change too large"<<std::endl; + } + else + // this equation would be correct if the bulk volume could change (Vol_new = Vol_init *(1+div u)), however, we + // have a constant bulk volume therefore we should apply phi_eff = phi_init + div u + // but this causes convergence problems. Since div u is very small here the chosen relation is + // assumed to be a good approximation + (*this)[scvIdx].effPorosity = ((*this)[scvIdx].porosity() + (*this)[scvIdx].divU)/(1.0 + (*this)[scvIdx].divU); + } + else + (*this)[scvIdx].effPorosity = (*this)[scvIdx].porosity(); + } + } + + + const std::vector<Scalar>& dofValues() const + { + return dofValues_; + } + + Scalar& dofValues(int k) + { + return dofValues_[k]; + } + + const std::vector<Scalar>& prevValues() const + { + return prevValues_; + } + +private: + std::vector<Scalar> dofValues_; + std::vector<Scalar> prevValues_; +}; + +} // namespace Dumux + +#endif diff --git a/dumux/geomechanics/el2p/fluxvariables.hh b/dumux/geomechanics/el2p/fluxvariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..c7ec9f0c3e01cb061a8a3ed29f8513700c15ae9e --- /dev/null +++ b/dumux/geomechanics/el2p/fluxvariables.hh @@ -0,0 +1,270 @@ +// -*- 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 This file contains the calculation of all the fluxes over the surface of the + * finite volume that make up the volume, the mass and the momentum balance + * for the two-phase linear-elastic model. + * + * This means pressure, concentration and solid-displacement gradients, phase densities at + * the integration point, etc. + * + * This class inherits from the two-phase model FluxVariables + */ +#ifndef DUMUX_EL2P_FLUX_VARIABLES_HH +#define DUMUX_EL2P_FLUX_VARIABLES_HH + +#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> +#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> +#include "properties.hh" + +namespace Dumux +{ + +namespace Properties +{ +// forward declaration of properties +NEW_PROP_TAG(SpatialParams); +} +/*! + * \ingroup ElTwoPBoxModel + * \ingroup ImplicitFluxVariables + * \brief This template class contains the data which is required to + * calculate the fluxes over the surface of the + * finite volume that make up the volume, the mass and the momentum balance + * for the two-phase linear-elastic model. + * + * This means pressure, concentration and solid-displacement gradients, phase densities at + * the integration point, etc. + * + */ + template<class TypeTag> + class ElTwoPFluxVariables: public ImplicitDarcyFluxVariables<TypeTag> + { + typedef ImplicitDarcyFluxVariables<TypeTag> TwoPBase; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + enum + { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + + typedef typename GridView::ctype CoordScalar; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldVector<CoordScalar, dim> DimVector; + typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimMatrix; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; + + enum {numEq = GET_PROP_VALUE(TypeTag, NumEq)}; + + public: + /* + * \brief The constructor + * + * \param problem The problem + * \param element The finite element + * \param fvGeometry The finite-volume geometry in the fully implicit scheme + * \param fIdx The local index of the SCV (sub-control-volume) face + * \param elemVolVars The volume variables of the current element + * \param onBoundary A boolean variable to specify whether the flux variables + * are calculated for interior SCV faces or boundary faces, default=false + */ + ElTwoPFluxVariables(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : TwoPBase(problem, element, fvGeometry, fIdx, elemVolVars), + fvGeometry_(fvGeometry), faceIdx_(fIdx) + { + dU_ = Scalar(0); + timeDerivUNormal_ = Scalar(0); + + elTwoPGradients_(problem, element, elemVolVars); + calculateDDt_(problem, element, elemVolVars); + calculateK_(problem, element, elemVolVars); + } + ; + + public: + /*! + * \brief Return change of u [m] with time at integration point + * point. + */ + Scalar dU(int dimIdx) const + { + return dU_[dimIdx]; + } + + /*! + * \brief Return time derivative of u [m/s] in normal + * direction at integration point + */ + Scalar timeDerivUNormal() const + { + return timeDerivUNormal_; + } + + /* + * \brief Return the intrinsic permeability. + */ + const DimMatrix &intrinsicPermeability() const + { + return K_; + } + + /* + * \brief Return the gradient of the potential for each phase. + */ + DimVector potentialGrad(int phaseIdx) const + { + return this->potentialGrad_[phaseIdx]; + } + + const SCVFace &face() const + { + return fvGeometry_.subContVolFace[faceIdx_]; + } + + protected: + /*! + * \brief Calculation of the solid displacement gradients. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void elTwoPGradients_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; + typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; + const GridFunctionSpace& gridFunctionSpace = problem.model().jacobianAssembler().gridFunctionSpace(); + const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); + LocalFunctionSpace localFunctionSpace(gridFunctionSpace); + localFunctionSpace.bind(element); + // copy values of previous solution into prevSolutionValues Vector + std::vector<Scalar> prevSolutionValues(localFunctionSpace.size()); + // copy values of current solution into curSolutionValues Vector + std::vector<Scalar> curSolutionValues(localFunctionSpace.size()); + for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) + { + const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); + typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; + ordering.mapIndex(di.view(),ci); + prevSolutionValues[k] = problem.model().prevSol()[ci]; + curSolutionValues[k] = problem.model().curSol()[ci]; + } + + // type of function space for solid displacement vector + typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; + const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); + // number of degrees of freedom for each displacement value (here number of element vertices) + const unsigned int dispSize = displacementLFS.child(0).size(); + // type of function space of solid displacement value (one for each coordinate direction) + typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; + typedef typename ScalarDispLFS::Traits::FiniteElementType::Traits::LocalBasisType::Traits::RangeType RT_V; + + for(int coordDir = 0; coordDir < dim; ++coordDir) { + // get displacement function space for coordinate direction coordDir + const ScalarDispLFS & scalarDispLFS = displacementLFS.child(coordDir); + std::vector<RT_V> vShape(dispSize); + // evaluate shape functions of all element vertices for current integration point and write it into vector vShape + scalarDispLFS.finiteElement().localBasis().evaluateFunction(face().ipLocal, vShape); + + dU_[coordDir] = 0; + // subtract previous displacement value from current displacement value for each coordinate direction + // coordDir and for each node i and interpolate values at integration point via the shape function vShape. + // TODO: evaluation of prevVolVars should also be possible--> check + for (size_t i = 0; i < dispSize; i++){ + dU_[coordDir] += (elemVolVars[i].primaryVars()[(numEq - dim)+coordDir] + - prevSolutionValues[scalarDispLFS.localIndex(i)])*vShape[i]; + } + } + } + + /*! + * \brief Calculation of the time derivative of solid displacement + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateDDt_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + Scalar dt = problem.timeManager().timeStepSize(); + + DimVector tmp(0.0); + // calculate time derivative of solid displacement vector + for (int coordDir = 0; coordDir < dim; ++coordDir) + tmp[coordDir] = dU(coordDir) / dt; + + // multiply time derivative of solid displacement vector with + // normal vector of current scv-face + timeDerivUNormal_ = tmp * face().normal; + } + + /*! + * \brief Calculation the harmonic mean of the intrinsic permeability tensor + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateK_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + // calculate the mean intrinsic permeability + const SpatialParams &spatialParams = problem.spatialParams(); + spatialParams.meanK(K_, + spatialParams.intrinsicPermeability(element, + fvGeometry_, + face().i), + spatialParams.intrinsicPermeability(element, + fvGeometry_, + face().j)); + } + + const FVElementGeometry &fvGeometry_; + int faceIdx_; + + //! time derivative of solid displacement times normal vector at integration point + Scalar timeDerivUNormal_; + //! change of solid displacement with time at integration point + GlobalPosition dU_; + // intrinsic permeability + DimMatrix K_; + }; + +} // end namespace + +#endif diff --git a/dumux/geomechanics/el2p/indices.hh b/dumux/geomechanics/el2p/indices.hh new file mode 100644 index 0000000000000000000000000000000000000000..c0675daf9bf5070c13c576310187c8fe54a57984 --- /dev/null +++ b/dumux/geomechanics/el2p/indices.hh @@ -0,0 +1,58 @@ +// -*- 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 Defines the primary variable and equation indices used by + * the two-phase linear elasticity model. + */ +#ifndef DUMUX_ELASTIC2P_INDICES_HH +#define DUMUX_ELASTIC2P_INDICES_HH + +#include <dumux/geomechanics/elastic/indices.hh> +#include <dumux/porousmediumflow/2p/implicit/indices.hh> + +namespace Dumux +{ +// \{ + +namespace Properties +{ + +/*! + * \ingroup ElTwoPBoxModel + * \ingroup ImplicitIndices + * \brief The indices for the two-phase linear elasticity model. + * + * This class inherits from the TwoPIndices and from the ElasticIndices + */ + +// PVOffset is set to 0 for the TwoPIndices and to 2 for the ElasticIndices since +// the first two primary variables are the primary variables of the two-phase +// model followed by the primary variables of the elastic model +template <class TypeTag, +int formulation = 0, +int PVOffset = 2> +class ElTwoPIndices : public ElasticIndices<PVOffset>, public TwoPIndices<TypeTag,0> +{}; + +} +} + +#endif diff --git a/dumux/geomechanics/el2p/localjacobian.hh b/dumux/geomechanics/el2p/localjacobian.hh new file mode 100644 index 0000000000000000000000000000000000000000..67a960a31e5f04369f833bcd35d3956b6ba03397 --- /dev/null +++ b/dumux/geomechanics/el2p/localjacobian.hh @@ -0,0 +1,257 @@ +// -*- 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 Calculates the partial derivatives of the local residual for the Jacobian of the + * two-phase linear elasticity model. + */ +#ifndef DUMUX_EL2P_LOCAL_JACOBIAN_HH +#define DUMUX_EL2P_LOCAL_JACOBIAN_HH + +#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> +#include <dumux/implicit/localjacobian.hh> +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup ElTwoPBoxModel + * \brief Calculates the partial derivatives of the local residual for the Jacobian + * + * Except for the evalPartialDerivatives function all functions are taken from the + * base class ImplicitLocalJacobian + */ +template<class TypeTag> +class ElTwoPLocalJacobian : public ImplicitLocalJacobian<TypeTag> +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { + dim = GridView::dimension, + }; + 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, Scalar) Scalar; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx + }; + // copying a local jacobian is not a good idea + ElTwoPLocalJacobian(const ElTwoPLocalJacobian &); + +public: + ElTwoPLocalJacobian() {} + + /*! + * \brief Compute the partial derivatives to a primary variable at + * an degree of freedom. + * + * This method is overwritten here since this model requires a call of the model specific + * elementvolumevariables which updates the effective porosities correctly. + * + * 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 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, + int col, + int pvIdx) + { + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; + typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; + + // copy the values of the globalSol vector to the localFunctionSpace values of the current element + const GridFunctionSpace& gridFunctionSpace = this->problemPtr_->model().jacobianAssembler().gridFunctionSpace(); + const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); + LocalFunctionSpace localFunctionSpace(gridFunctionSpace); + localFunctionSpace.bind(this->element_()); + std::vector<Scalar> elementValues(localFunctionSpace.size()); + for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) + { + const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); + typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; + ordering.mapIndex(di.view(),ci); + elementValues[k] = this->problemPtr_->model().curSol()[ci]; + } + // pressure and saturation local function space (mass balance equations) + typedef typename LocalFunctionSpace::template Child<0>::Type PressSatLFS; + const PressSatLFS& pressSatLFS = localFunctionSpace.template child<0>(); + // local function space for pressure + typedef typename PressSatLFS::template Child<0>::Type PressLFS; + const PressLFS& pressLFS = pressSatLFS.template child<0>(); + // local function space for saturation + typedef typename PressSatLFS::template Child<1>::Type SatLFS; + const SatLFS& satLFS = pressSatLFS.template child<1>(); + // local function space for solid displacement + typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; + const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); + typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; + + //primary variable vector priVars for each vertex + PrimaryVariables priVars; + priVars[pressureIdx] = elementValues[pressLFS.localIndex(col)]; + priVars[saturationIdx] = elementValues[satLFS.localIndex(col)]; + for (int coordDir = 0; coordDir < dim; coordDir++) + { + const ScalarDispLFS& scalarDispLFS = displacementLFS.child(coordDir); + priVars[Indices::u(coordDir)] = elementValues[scalarDispLFS.localIndex(col)]; + } + + VolumeVariables origVolVars(this->curVolVars_[col]); + this->curVolVars_[col].setEvalPoint(&origVolVars); + Scalar eps = this->numericEpsilon(col, pvIdx); + Scalar delta = 0; + + if (this->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 + this->curVolVars_[col].update(priVars, + this->problem_(), + this->element_(), + this->fvElemGeom_, + col, + false); + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_, + false); + + this->localResidual().eval(this->element_(), + this->fvElemGeom_, + this->prevVolVars_, + this->curVolVars_, + this->bcTypes_); + + // store the residual + partialDeriv = this->localResidual().residual(); + storageDeriv = this->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 = this->residual_; + storageDeriv = this->storageTerm_[col]; + } + + + if (this->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 + this->curVolVars_[col].update(priVars, + this->problem_(), + this->element_(), + this->fvElemGeom_, + col, + false); + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_, + false); + this->localResidual().eval(this->element_(), + this->fvElemGeom_, + this->prevVolVars_, + this->curVolVars_, + this->bcTypes_); + partialDeriv -= this->localResidual().residual(); + storageDeriv -= this->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 -= this->residual_; + storageDeriv -= this->storageTerm_[col]; + } + + // divide difference in residuals by the magnitude of the + // deflections between the two function evaluation +// if(partialDeriv[col][pvIdx] == -350045) + + partialDeriv /= delta; + storageDeriv /= delta; + // restore the orignal state of the element's volume variables + this->curVolVars_[col] = origVolVars; + // update the effective porosities + this->curVolVars_.updateEffPorosity(this->problem_(), + this->element_(), + this->fvElemGeom_, + false); + +#if HAVE_VALGRIND + for (unsigned i = 0; i < partialDeriv.size(); ++i) + Valgrind::CheckDefined(partialDeriv[i]); +#endif + } +}; +} + +#endif diff --git a/dumux/geomechanics/el2p/localoperator.hh b/dumux/geomechanics/el2p/localoperator.hh new file mode 100644 index 0000000000000000000000000000000000000000..8903dcdf920e82ac075d8eec3411cdd6fafec29d --- /dev/null +++ b/dumux/geomechanics/el2p/localoperator.hh @@ -0,0 +1,635 @@ +// -*- 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 This file contains a local operator for PDELab which + * wraps the contributions from + * el2plocalresidual (box discretized mass balances) + * and alphaMomentum (FE discretized momentum balance). + */ +#ifndef DUMUX_EL2P_LOCAL_OPERATOR_HH +#define DUMUX_EL2P_LOCAL_OPERATOR_HH + +#include<dune/common/version.hh> +#include<dune/geometry/quadraturerules.hh> + +#include<dune/pdelab/localoperator/pattern.hh> +#include<dune/pdelab/localoperator/flags.hh> +#include<dune/pdelab/localoperator/defaultimp.hh> +#include<dune/pdelab/gridfunctionspace/localvector.hh> +#include<dune/pdelab/common/geometrywrapper.hh> +#include "properties.hh" + +namespace Dumux { + +namespace PDELab { + +/*! + * \brief A local operator for PDELab which wraps the contributions from + * el2plocalresidual (box discretized mass balances) + * and alphaMomentum (FE discretized momentum balance). + */ +template<class TypeTag> +class El2PLocalOperator + : + public Dune::PDELab::FullVolumePattern, + public Dune::PDELab::LocalOperatorDefaultFlags +{ + // copying the local operator for PDELab is not a good idea + El2PLocalOperator(const El2PLocalOperator &); + + typedef typename GET_PROP_TYPE(TypeTag, Model) Model; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity::Geometry::JacobianInverseTransposed JacobianInverseTransposed; + typedef typename GridView::Intersection Intersection; + typedef typename Dune::PDELab::IntersectionGeometry<Intersection>::ctype DT; + + enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; + enum{dim = GridView::dimension}; + enum{dimWorld = GridView::dimensionworld}; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + + enum { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx + }; + +public: + // pattern assembly flags + enum { doPatternVolume = true }; + + // residual assembly flags + enum { doAlphaVolume = true }; + + /*! + * \param model The physical model for the box scheme. + */ + El2PLocalOperator(Model &model) + : model_(model) + {} + + /*! + * \brief Volume integral depending on test and ansatz functions + * + * \tparam EG The entity geometry type from PDELab + * \tparam LFSU The type of the local function space of the ansatz functions + * \tparam X The type of the container for the coefficients for the ansatz functions + * \tparam LFSV The type of the local function space of the test functions + * \tparam R The range type (usually FieldVector<double>) + * + * \param eg The entity geometry object + * \param lfsu The local function space object of the ansatz functions + * \param x The object of the container for the coefficients for the ansatz functions + * \param lfsv The local function space object of the test functions + * \param r The object storing the volume integral + */ + template<typename EG, typename LFSU, typename X, typename LFSV, typename R> + void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, + const LFSV& lfsv, R& r) const + { + typedef typename LFSU::Traits::SizeType size_type; + + // evaluate the local residual of the box mass balance equation for the current element + model_.localResidual().eval(eg.entity()); + + // pressure and saturation local function space (mass balance equations) + typedef typename LFSU::template Child<0>::Type PressSatLFS; + // local function space for pressure + typedef typename PressSatLFS::template Child<0>::Type PressLFS; + const PressSatLFS& pressSatLFS = lfsu.template child<0>(); + const PressLFS& pressLFS = pressSatLFS.template child<0>(); + // local function space for saturation + typedef typename PressSatLFS::template Child<1>::Type SatLFS; + const SatLFS& satLFS = pressSatLFS.template child<1>(); + + unsigned int numScv = eg.entity().subEntities(dim); + + for (size_type i = 0; i < (numEq-dim) * numScv; i++) + { + // retrieve the local residual value for vertex=i%Vertices and equation i/numScv (here 0 or 1) + Scalar tmp = model_.localResidual().residual(i%numScv)[i/numScv]; + // get residual for brine phase mass balance equation + if(i < numScv) + r.rawAccumulate(pressLFS, i, tmp); + // get residual for CO2 phase mass balance equation + else + r.rawAccumulate(satLFS,i-numScv, tmp); + } + // get residual for momentum balance equation + alphaMomentum(eg, lfsu, x, lfsv, r); + } + + + /*! + * \brief Calculate the local residual of the momentum balance equation + * with the finite element method. This requires numerical + * integration which is done via a quadrature rule. + * + * \tparam EG The entity geometry type from PDELab + * \tparam LFSU The type of the local function space of the ansatz functions + * \tparam X The type of the container for the coefficients for the ansatz functions + * \tparam LFSV The type of the local function space of the test functions + * \tparam R The range type (usually FieldVector<double>) + * + * \param eg The entity geometry object + * \param lfsu The local function space object of the ansatz functions + * \param x The object of the container for the coefficients for the ansatz functions + * \param lfsv The local function space object of the test functions + * \param r The object storing the volume integral + * + * + */ + template<typename EG, typename LFSU, typename X, typename LFSV, typename R> + void alphaMomentum (const EG& eg, const LFSU& lfsu, const X& x, + const LFSV& lfsv, R& r) const + { + FVElementGeometry fvGeometry; + fvGeometry.update(model_.problem().gridView(), eg.entity()); + // retrieve lame parameters for calculation of effective stresses + const Dune::FieldVector<Scalar,2> lameParams = model_.problem().spatialParams().lameParams(eg.entity(), fvGeometry, 0); + Scalar lambda = lameParams[0]; + Scalar mu = lameParams[1]; + // retrieve materialParams for calculate of capillary pressure + const MaterialLawParams& materialParams = + model_.problem().spatialParams().materialLawParams(eg.entity(), fvGeometry, 0); + // retrieve initial porosity + Scalar porosity = model_.problem().spatialParams().porosity(eg.entity(), fvGeometry, 0); + + // order of quadrature rule + const int qorder = 3; + + // extract local function spaces + // pressure and saturation local function space (mass balance equations) + typedef typename LFSU::template Child<0>::Type PressSatLFS; + const PressSatLFS& pressSatLFS = lfsu.template child<0>(); + // local function space for pressure + typedef typename PressSatLFS::template Child<0>::Type PressLFS; + const PressLFS& pressLFS = pressSatLFS.template child<0>(); + const unsigned int pressSize = pressLFS.size(); + // local function space for saturation + typedef typename PressSatLFS::template Child<1>::Type SatLFS; + const SatLFS& satLFS = pressSatLFS.template child<1>(); + // local function space for solid displacement + typedef typename LFSU::template Child<1>::Type DisplacementLFS; + typedef typename DisplacementLFS::template Child<0>::Type DisplacementScalarLFS; + const DisplacementLFS& displacementLFS = lfsu.template child<1>(); + const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<0>(); + const unsigned int dispSize = displacementLFS.template child<0>().size(); + + // domain and range field type + typedef typename DisplacementScalarLFS::Traits::FiniteElementType:: + Traits::LocalBasisType::Traits::RangeFieldType RF; + typedef typename DisplacementScalarLFS::Traits::FiniteElementType:: + Traits::LocalBasisType::Traits::RangeType RT_V; + typedef typename DisplacementScalarLFS::Traits::FiniteElementType:: + Traits::LocalBasisType::Traits::JacobianType JacobianType_V; + typedef typename PressLFS::Traits::FiniteElementType:: + Traits::LocalBasisType::Traits::DomainFieldType DF; + typedef typename PressLFS::Traits::FiniteElementType:: + Traits::LocalBasisType::Traits::RangeType RT_P; + + // select quadrature rule for the element geometry type and with the order=qorder + const auto geometry = eg.geometry(); + Dune::GeometryType geomType = geometry.type(); + const Dune::QuadratureRule<DF,dim>& rule = Dune::QuadratureRules<DF,dim>::rule(geomType,qorder); + + // loop over quadrature points + for (typename Dune::QuadratureRule<DF,dim>::const_iterator it=rule.begin(); it!=rule.end(); ++it) + { + // evaluate reference element gradients of shape functions at quadrature point + // (we assume Galerkin method lfsu=lfsv) + std::vector<JacobianType_V> vGradRef(dispSize); + uScalarLFS.finiteElement().localBasis().evaluateJacobian(it->position(),vGradRef); + + + // get inverse transposed jacobian for quadrature point + const JacobianInverseTransposed jacobian = geometry.jacobianInverseTransposed(it->position()); + + // calculate shape function gradients at the quadrature point in global coordinates. This is done + // by multiplying the reference element shape functions with the inverse transposed jacobian + std::vector<Dune::FieldVector<RF,dim> > vGrad(dispSize); + for (size_t i = 0; i < dispSize; i++) + { + vGrad[i] = 0.0; + jacobian.umv(vGradRef[i][0],vGrad[i]); + } + + // calculate the gradient of the solid displacement vector uGrad + // x(uLFS,i) is the solid displacement entry of the solution vector + // for element vertex i and coordinate direction coordDir + + Dune::FieldMatrix<RF,dim,dim> uGrad(0.0); + for(int coordDir = 0; coordDir < dim; ++coordDir) { + const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); + // compute gradient of u + for (size_t i = 0; i < dispSize; i++) + uGrad[coordDir].axpy(x(uLFS,i),vGrad[i]); + } + // calculate the strain tensor epsilon + Dune::FieldMatrix<RF,dim,dim> epsilon; + for(int i = 0; i < dim; ++i) + for(int j = 0; j < dim; ++j) + epsilon[i][j] = 0.5*(uGrad[i][j] + uGrad[j][i]); + + RF traceEpsilon = 0; + for(int i = 0; i < dim; ++i) + traceEpsilon += epsilon[i][i]; + + // calculate the effective stress tensor effStress + Dune::FieldMatrix<RF,dim,dim> effStress(0.0); + for(int i = 0; i < dim; ++i) + { + effStress[i][i] = lambda*traceEpsilon; + for(int j = 0; j < dim; ++j) + effStress[i][j] += 2.0*mu*epsilon[i][j]; + } + + // retrieve the shape functions for interpolating the primary variables at the + // current quadrature point + std::vector<RT_P> q(pressSize); + pressLFS.finiteElement().localBasis().evaluateFunction(it->position(),q); + + RT_P pw(0.0); + RT_P sn(0.0); + RT_P ux(0.0); + RT_P uy(0.0); + RT_P uz(0.0); + + // interpolate primary variables at current quadrature point + for (size_t i = 0; i < pressLFS.size(); i++) + { + pw += x(pressLFS,i) * q[i]; + sn += x(satLFS,i) * q[i]; + ux += x(displacementLFS.child(0),i) * q[i]; + if (dim > 1) + uy += x(displacementLFS.child(1),i) * q[i]; + if (dim > 2) + uz += x(displacementLFS.child(2),i) * q[i]; + } + RT_P sw = 1.0 - sn; + RT_P pn = pw + MaterialLaw::pc(materialParams, sw); + RT_P pEff; + + const GlobalPosition& globalPos = geometry.global(it->position()); + + // calculate change in effective pressure with respect to initial conditions pInit (pInit is negativ) + pEff = pw*sw + pn*sn + model_.problem().pInit(globalPos, it->position(), eg.entity()); + RF uDiv = traceEpsilon; + RF porosityEff; + + // assume deformation induced porosity changes + if(model_.problem().coupled() == true){ + if (porosity + uDiv < 1e-3*porosity){ + DUNE_THROW(Dumux::NumericalProblem, "volume change too large"); + } + else + // this equation would be correct if the bulk volume could change (Vol_new = Vol_init * (1+div u)), however, we + // have a constant bulk volume therefore we should apply phi_eff = phi_init + div u + // but this causes convergence problems. Since div u is very small here the chosen relation is + // assumed to be a good approximation + porosityEff = (porosity + uDiv)/(1.0 + uDiv); + } + // neglect deformation induced porosity changes + else + porosityEff = porosity; + + // fill primary variable vector for current quadrature point + PrimaryVariables primVars; + + primVars[wPhaseIdx] = pw; + primVars[nPhaseIdx] = sn; + primVars[Indices::uxIdx] = ux; + if (dim > 1) + primVars[Indices::uyIdx] = uy; + if (dim > 2) + primVars[Indices::uzIdx] = uz; + + VolumeVariables volVars; + // evaluate volume variables for this quadrature point + // TODO / NOTE: this overwrites the entries of the volumevariables of node 0 + // and can cause errors + volVars.update(primVars, model_.problem(), eg.entity(), fvGeometry, 0, false); + + // calculate the density difference for the gravity term + RF rhoDiff = volVars.density(nPhaseIdx) - volVars.density(wPhaseIdx); + + // geometric weight need for quadrature rule evaluation (numerical integration) + RF qWeight = it->weight() * geometry.integrationElement(it->position()); + + // evaluate basis functions + std::vector<RT_V> vBasis(dispSize); + displacementLFS.child(0).finiteElement().localBasis().evaluateFunction(it->position(), vBasis); + + for(int coordDir = 0; coordDir < dim; ++coordDir) { + const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); + // assemble momentum balance equation + for (size_t i = 0; i < dispSize; i++){ + // multiply effective stress with gradient of weighting function and geometric weight of quadrature rule + Scalar tmp = (effStress[coordDir] * vGrad[i]) * qWeight; + r.rawAccumulate(uLFS,i,tmp); + + // subtract effective pressure change contribution multiplied with gradient of weighting function + // and geometric weight of quadrature rule (soil mechanics sign conventions, compressive stresses are negative) + tmp = -(pEff * vGrad[i][coordDir]) * qWeight; + r.rawAccumulate(uLFS,i,tmp); + + // evaluate gravity term (soil mechanics sign conventions, compressive stresses are negative) + // multiplied with weighting function and geometric weight of quadrature rule. + // This assumes that the solid phase density remains constant, that the changes in porosity are very small, + // and that the density of the brine phase remains constant + tmp = sn*porosityEff*rhoDiff*model_.problem().gravity()[coordDir]*vBasis[i]* qWeight; + r.rawAccumulate(uLFS,i,tmp); + } + } + } + // include boundary conditions + // iterate over element intersections of codim dim-1 + for (const auto& intersection : Dune::intersections(model_.problem().gridView(), eg.entity())) + { + // handle only faces on the boundary + if (!intersection.boundary()) + continue; + + // select quadrature rule for intersection faces (dim-1) + Dune::GeometryType gtface = intersection.geometryInInside().type(); + const Dune::QuadratureRule<DF,dim-1>& faceRule = Dune::QuadratureRules<DF,dim-1>::rule(gtface,qorder); + + // get face index of this intersection + int fIdx = intersection.indexInInside(); + // get dimension of face + const int dimIs = Dune::PDELab::IntersectionGeometry<Intersection>::Entity::Geometry::mydimension; + + // get reference element for intersection geometry (reference element for face if dim = 3) + const Dune::ReferenceElement<DT,dimIs>& refElement = Dune::ReferenceElements<DT,dimIs>::general(geomType); + // get reference element for edges of intersection geometry (reference element for edge if dim = 3), needed for Dirichlet BC + const Dune::ReferenceElement<DT,dimIs-1> &face_refElement = + Dune::ReferenceElements<DT,dimIs-1>::general(intersection.geometryInInside().type()); + + // Treat Neumann boundary conditions + // loop over quadrature points and integrate normal stress changes (traction changes) + for (typename Dune::QuadratureRule<DF,dim-1>::const_iterator it=faceRule.begin(); it!=faceRule.end(); ++it) + { + // position of quadrature point in local coordinates of element + DimVector local = intersection.geometryInInside().global(it->position()); + + GlobalPosition globalPos = geometry.global(local); + + // evaluate boundary condition type + BoundaryTypes boundaryTypes; + model_.problem().boundaryTypesAtPos(boundaryTypes, globalPos); + + // skip rest if we are on Dirichlet boundary + if (!boundaryTypes.hasNeumann()) + continue; + + // evaluate basis functions of all all element vertices for quadrature point location "local" + std::vector<RT_V> vBasis(dispSize); + displacementLFS.child(0).finiteElement().localBasis().evaluateFunction(local, vBasis); + + // evaluate stress boundary condition. The stress change is assumed to be in normal direction (i.e. traction) + PrimaryVariables traction; + model_.problem().neumannAtPos(traction, globalPos); + + // get quadrature rule weight for intersection + const RF qWeight = it->weight() * intersection.geometry().integrationElement(it->position()); + + for(unsigned int coordDir=0; coordDir<dim; ++coordDir){ + const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); + // get the traction values for the current quadrature point, + // multiply it with the basis function and the quadrature rule weight + // and add it to the residual + if (boundaryTypes.isNeumann(Indices::momentum(coordDir))) + for (size_t i = 0; i < dispSize; i++){ + Scalar tmp = -traction[Indices::momentum(coordDir)] * vBasis[i] * qWeight; + r.rawAccumulate(uLFS,i,tmp); + } + + } + } + + // Treat Dirichlet boundary conditions, for Dirichlet boundaries we need to check vertices + // first do loop over degrees of freedom for displacement vector entry, then check codim of this degree of freedom + // then do loop over the current intersection face for the degrees of freedom with the given codim + // compare the subentity of the element loop with the subentity of the intersection face loop + // if the subentities are identical retrieve the coordinates of the intersection face subentity and evaluate the boundary + // condition type and if it is a Dirichlet boundary condition then retrieve the Dirichlet value. + // subtract the Dirichlet value from the corresponding solution vector entry (for this the outer element loop is needed) + // and also subtract the residual value which has already been calculated for this degree of freedom + // write the result into the residual + + for(unsigned int coordDir=0; coordDir<dim; ++coordDir){ + const DisplacementScalarLFS& uLFS = displacementLFS.child(coordDir); + + // loop over number of element vertices + for (size_t i = 0; i < dispSize; i++) + { + // Get the codim to which this degree of freedom is attached to (should be a vertex) + unsigned int codim = displacementLFS.child(0).finiteElement().localCoefficients().localKey(i).codim(); + // if we are within the element do nothing (this could happen if second order approximations are applied) + if (codim==0) continue; + + // iterate over number of degrees of freedom with the given codim which are attached to the current intersection face + for (int j = 0; j < refElement.size(fIdx,1,codim); j++) + { // check if degree of freedom is located on a vertex of the current intersection (boundary face) + if (displacementLFS.child(0).finiteElement().localCoefficients().localKey(i).subEntity() == + refElement.subEntity(fIdx,1,j,codim)) + { + // get local coordinate for this degree of freedom +// this doesn't work: DimVector local = intersection.geometryInInside().global(face_refElement.position(j,codim-1)); + DimVector local = refElement.template geometry<1>(fIdx).global(face_refElement.position(j, codim-1)); + + GlobalPosition globalPos = geometry.global(local); + + // evaluate boundary condition type + BoundaryTypes boundaryTypes; + model_.problem().boundaryTypesAtPos(boundaryTypes, globalPos); + + if (boundaryTypes.isDirichlet(Indices::u(coordDir))) + { + // set value of dirichlet BC + PrimaryVariables dirichletValues; + model_.problem().dirichletAtPos(dirichletValues, globalPos); + // retrieve residual value which has already been calculated for the given vertex before it + // was clear that we are on a Dirichlet boundary + Scalar tmpResVal = r.container().base()[(numEq-dim)*dispSize + coordDir*dispSize + i]; + // subtract the dirichletValue and the stored residual value from the solution vector entry + // if the solution vector entry equals the dirichletValue the residual will be zero + Scalar tmp = x(uLFS,i) - dirichletValues[Indices::u(coordDir)] - tmpResVal; + // write result into the residual vector + r.rawAccumulate(uLFS,i,tmp); + } + } + } + } + } + } + } + + /*! + * \brief Jacobian of volume term + * + * \tparam EG The entity geometry type from PDELab + * \tparam LFSU The type of the local function space of the ansatz functions + * \tparam X The type of the container for the coefficients for the ansatz functions + * \tparam LFSV The type of the local function space of the test functions + * \tparam M The matrix type + * + * \param eg The entity geometry object + * \param lfsu The local function space object of the ansatz functions + * \param x The object of the container for the coefficients for the ansatz functions + * \param lfsv The local function space object of the test functions + * \param mat The object containing the local jacobian matrix + */ + template<typename EG, typename LFSU, typename X, typename LFSV, typename M> + void jacobian_volume (const EG& eg, + const LFSU& lfsu, + const X& x, + const LFSV& lfsv, + M& mat) const + { + typedef typename LFSU::Traits::SizeType size_type; + + model_.localJacobian().assemble(eg.entity()); + // pressure and saturation local function space (mass balance equations) + typedef typename LFSU::template Child<0>::Type PressSatLFS; + typedef typename PressSatLFS::template Child<0>::Type PressLFS; + const PressSatLFS& pressSatLFS = lfsu.template child<0>(); + const PressLFS& pressLFS = pressSatLFS.template child<0>(); + typedef typename PressSatLFS::template Child<1>::Type SatLFS; + const SatLFS& satLFS = pressSatLFS.template child<1>(); + // local function space for solid displacement + typedef typename LFSU::template Child<1>::Type DisplacementLFS; + typedef typename DisplacementLFS::template Child<0>::Type DisplacementScalarLFS; + const DisplacementLFS& displacementLFS = lfsu.template child<1>(); + + // type of local residual vector + typedef typename M::value_type R; + typedef Dune::PDELab::LocalVector<R> LocalResidualVector; + typedef Dune::PDELab::WeightedVectorAccumulationView<LocalResidualVector> ResidualView; + + unsigned int numScv = eg.entity().subEntities(dim); + + // loop over all degrees of freedom of the current element + for (size_type j = 0; j < numScv*numEq; j++) + { + // assemble entries for mass balance equations + for (size_type i = 0; i < (numEq-dim)*numScv; i++) + { + // local jacobian value of location idxI=i%numScv, idxJ=j%numScv for equation i/numScv and unknown j/numScv + Scalar tmp = (model_.localJacobian().mat(i%numScv,j%numScv))[i/numScv][j/numScv]; + // mass balance entries for pressure + if (j < numScv){ + if(i < numScv) + mat.rawAccumulate(pressLFS,i,pressLFS,j,tmp); + else + mat.rawAccumulate(satLFS,i-numScv,pressLFS,j,tmp); + } + // mass balance entries for saturation + else if (j < 2*numScv){ + if(i < numScv) + mat.rawAccumulate(pressLFS,i,satLFS,j-numScv,tmp); + else + mat.rawAccumulate(satLFS,i-numScv,satLFS,j-numScv,tmp); + } + // mass balance entries for solid displacement in x-direction + else if (j < 3*numScv) + { + const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<0>(); + if(i < numScv) + mat.rawAccumulate(pressLFS,i,uScalarLFS,j-2*numScv,tmp); + else + mat.rawAccumulate(satLFS,i-numScv,uScalarLFS,j-2*numScv,tmp); + } + // mass balance entries for solid displacement in y-direction + else if (j < 4*numScv && dim >=2) + { + const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<1>(); + if(i < numScv) + mat.rawAccumulate(pressLFS,i,uScalarLFS,j-3*numScv,tmp); + else + mat.rawAccumulate(satLFS,i-numScv,uScalarLFS,j-3*numScv,tmp); + } + // mass balance entries for solid displacement in z-direction + else if(j < 5*numScv && dim >=3) + { + const DisplacementScalarLFS& uScalarLFS = displacementLFS.template child<dim-1>(); + if(i < numScv) + mat.rawAccumulate(pressLFS,i,uScalarLFS,j-(numEq-1)*numScv,tmp); + else + mat.rawAccumulate(satLFS,i-numScv,uScalarLFS,j-(numEq-1)*numScv,tmp); + } + + } + } + + // calculate local jacobian entries and assemble for momentum balance equation + const int m=lfsv.size(); + const int n=lfsu.size(); + + X u(x); + LocalResidualVector down(mat.nrows(),0); + + // evaluate momentum residual for momentum balance equation + ResidualView downView = down.weightedAccumulationView(1.0); + alphaMomentum(eg, lfsu, u, lfsv, downView); + + // loop over all columns (number of element vertices * number of equations) + for (int j = 0; j < n; j++) + { + // vary the solution vector entry (lfsu,j) by a small value delta (forward differencing) + // this comprises presure, saturation, ux, uy and uz + Scalar delta = 1e-4*(1.0+std::abs(u(lfsu,j))); + u(lfsu,j) += delta; + + // evaluate momentum balance residual for the varied solution vector + LocalResidualVector up(mat.nrows(), 0); + ResidualView upView = up.weightedAccumulationView(1.0); + alphaMomentum(eg, lfsu, u, lfsv, upView); + + // calculate partial derivative for momentum balance equations and assemble + for (int i = (numEq-dim)*numScv; i < m; i++) + { + Scalar entry = (up(lfsv, i) - down(lfsv, i))/delta; + // accumulate resulting partial derivatives into jacobian + mat.rawAccumulate(lfsv,i, lfsu,j,entry); + } + + // reset solution + u(lfsu,j) = x(lfsu,j); + } + } + +private: + Model& model_; +}; + +} // namespace PDELab +} // namespace Dumux + +#endif diff --git a/dumux/geomechanics/el2p/localresidual.hh b/dumux/geomechanics/el2p/localresidual.hh new file mode 100644 index 0000000000000000000000000000000000000000..f72e06adf29cc4c727d72265eab907b8a3999fff --- /dev/null +++ b/dumux/geomechanics/el2p/localresidual.hh @@ -0,0 +1,317 @@ +// -*- 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 Element-wise calculation of the residual for the linear elastic, + * two-phase model in the fully implicit scheme. + */ +#ifndef DUMUX_ELASTIC2P_LOCAL_RESIDUAL_HH +#define DUMUX_ELASTIC2P_LOCAL_RESIDUAL_HH + +#include <dune/pdelab/gridfunctionspace/localfunctionspace.hh> +#include <dumux/implicit/box/localresidual.hh> +#include "properties.hh" + +namespace Dumux { +/*! + * \ingroup ElTwoPModel + * \ingroup ImplicitLocalResidual + * + * \brief Element-wise calculation of the Jacobian matrix for problems + * using the two-phase linear-elasticity fully implicit model. + */ +template<class TypeTag> +class ElTwoPLocalResidual: public BoxLocalResidual<TypeTag> { +protected: + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + enum { + dim = GridView::dimension + }; + + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + typedef Dune::FieldVector<Scalar, dim> DimVector; + + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum { + numFluidPhases = GET_PROP_VALUE(TypeTag, NumPhases) + }; + enum { + contiWEqIdx = Indices::contiWEqIdx, + contiNEqIdx = Indices::contiNEqIdx, + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx + }; + //TODO: delete this if not required + // only effective porosity update in element variables doesn't work + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; + typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; + +public: + /*! + * \brief Constructor. Sets the upwind weight. + */ + ElTwoPLocalResidual() { + // retrieve the upwind weight for the mass conservation equations. Use the value + // specified via the property system as default, and overwrite + // it by the run-time parameter from the Dune::ParameterTree + massUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, + MassUpwindWeight); + } + ; + + /*! + * \brief Evaluate the amount all conservation quantities + * (e.g. phase mass) within a finite sub-control volume. + * + * \param storage The phase mass within the sub-control volume + * \param scvIdx The SCV (sub-control-volume) index + * \param usePrevSol Evaluate function with solution of current or previous time step + */ + void computeStorage(PrimaryVariables &storage, int scvIdx, + bool usePrevSol) const { + // if flag usePrevSol is set, the solution from the previous + // time step is used, otherwise the current solution is + // used. The secondary variables are used accordingly. This + // is required to compute the derivative of the storage term + // using the implicit Euler method. + const ElementVolumeVariables &elemVolVars = + usePrevSol ? this->prevVolVars_() : this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[scvIdx]; + + storage = Scalar(0); + + // wetting phase mass + storage[contiWEqIdx] = volVars.density(wPhaseIdx) + * volVars.saturation(wPhaseIdx) * volVars.effPorosity; + // non-wetting phase mass + storage[contiNEqIdx] = volVars.density(nPhaseIdx) + * volVars.saturation(nPhaseIdx) * volVars.effPorosity; + } + + /*! + * \brief Evaluates the mass flux over a face of a sub-control + * volume. + * + * \param flux The flux over the SCV (sub-control-volume) face for each phase + * \param fIdx The index of the SCV face + * \param onBoundary A boolean variable to specify whether the flux variables + * are calculated for interior SCV faces or boundary faces, default=false + */ + void computeFlux(PrimaryVariables &flux, int fIdx, + const bool onBoundary = false) const { + //TODO: delete this if not required + // adapts the effective porosity node-wise for evaluation of derivatives. + // At the moment computeFlux is called before computeStorage so effPorosity in + // computeStorage should also be correct. + +// if (fIdx == 0) +// { +// int numScv = this->element_().template count<dim> (); +// +// LocalFunctionSpace localFunctionSpace(this->problem_().model().jacobianAssembler().gridFunctionSpace()); +// localFunctionSpace.bind(this->element_()); +// std::vector<Scalar> values; +// localFunctionSpace.vread(this->problem_().model().curSol(), values); +// +// +// typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; +// const DisplacementLFS& displacementLFS = localFunctionSpace.template child<1>(); +// const unsigned int dispSize = displacementLFS.child(0).size(); +// +// typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; +// typedef typename ScalarDispLFS::Traits::FiniteElementType:: +// Traits::LocalBasisType::Traits::JacobianType JacobianType_V; +// typedef typename ScalarDispLFS::Traits::FiniteElementType:: +// Traits::LocalBasisType::Traits::RangeFieldType RF; +// typedef typename ScalarDispLFS::Traits::FiniteElementType:: +// Traits::LocalBasisType::Traits::DomainFieldType DF; +// +// // calculate the divergence of the displacement +// for (int scvIdx = 0; scvIdx < numScv; scvIdx++) +// { +// const DimVector& scvCenter = this->fvGeometry_().subContVol[scvIdx].localCenter; +// +// // evaluate gradient of displacement shape functions +// std::vector<JacobianType_V> vRefShapeGradient(dispSize); +// displacementLFS.child(0).finiteElement().localBasis().evaluateJacobian(scvCenter, vRefShapeGradient); +// +// // transform gradient to physical element +// const Dune::FieldMatrix<DF,dim,dim> jacInvT = this->element_().geometry().jacobianInverseTransposed(scvCenter); +// std::vector<Dune::FieldVector<RF,dim> > vShapeGradient(dispSize); +// for (size_t i = 0; i < dispSize; i++) +// { +// vShapeGradient[i] = 0.0; +// jacInvT.umv(vRefShapeGradient[i][0],vShapeGradient[i]); +// } +// +// // calculate gradient of current displacement +// typedef Dune::FieldMatrix<RF, dim, dim> Tensor; +// Tensor uGradient(0.0); +// for(int comp = 0; comp < dim; ++comp){ +// const ScalarDispLFS & scalarDispLFS = displacementLFS.child(comp); +// +// for (size_t i = 0; i < 8; i++) +// uGradient[comp].axpy(this->curVolVars_()[i].displacement(comp), vShapeGradient[i]); +// +// for (size_t i = 8; i < scalarDispLFS.size(); i++) +// uGradient[comp].axpy(values[scalarDispLFS.localIndex(i)], vShapeGradient[i]); +// } +// +// this->curVolVars_()[scvIdx].divU = 0.0; +// for (int comp = 0; comp < dim; comp++) +// this->curVolVars_()[scvIdx].divU += uGradient[comp][comp]; +// if(this->problem_().coupled() == true){ +// if (this->curVolVars_()[scvIdx].divU < - this->curVolVars_()[scvIdx].porosity()){ +// this->curVolVars_()[scvIdx].effPorosity = this->curVolVars_()[scvIdx].porosity(); +// std::cout<<"volume change too large"<<std::endl; +// } +// else{ +// this->curVolVars_()[scvIdx].effPorosity = (this->curVolVars_()[scvIdx].porosity() +// + this->curVolVars_()[scvIdx].divU)/(1.0 + this->curVolVars_()[scvIdx].divU);} +// } +// else +// this->curVolVars_()[scvIdx].effPorosity = this->curVolVars_()[scvIdx].porosity(); +// } +// } + + FluxVariables fluxVars(this->problem_(), this->element_(), + this->fvGeometry_(), fIdx, this->curVolVars_()); + + flux = 0; + this->computeAdvectiveFlux(flux, fluxVars); + } + + /*! + * \brief Evaluates the advective mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The advective flux over the sub-control-volume face for each phase + * \param fluxVars The flux variables at the current SCV + * + * This method is called by compute flux and is mainly there for + * derived models to ease adding equations selectively. + */ + void computeAdvectiveFlux(PrimaryVariables &flux, + const FluxVariables &fluxVars) const { + // calculate effective permeability based on effective porosity + // according to the relation given in Rutqvist and Tsang (2002) + // this evaluation should be moved to another location + DimVector tmpVec; + DimMatrix Keff, Keff_i, Keff_j; + + Scalar exp_i, exp_j; + // evaluate effective permeabilities for nodes i and j based on the + // effective porosities, the initial porosities and the initial permeabilities + exp_i = + 22.2 + * (this->curVolVars_()[fluxVars.face().i].effPorosity + / this->curVolVars_()[fluxVars.face().i].porosity() + - 1); + exp_j = + 22.2 + * (this->curVolVars_()[fluxVars.face().j].effPorosity + / this->curVolVars_()[fluxVars.face().j].porosity() + - 1); + Keff_i = fluxVars.intrinsicPermeability(); + Keff_i *= exp(exp_i); + Keff_j = fluxVars.intrinsicPermeability(); + Keff_j *= exp(exp_j); + + // calculate the mean effective permeability at integration point + this->problem_().spatialParams().meanK(Keff, Keff_i, Keff_j); + + // loop over all phases + for (int phaseIdx = 0; phaseIdx < numFluidPhases; ++phaseIdx) { + // data attached to upstream and the downstream vertices + // of the current phase + // calculate the flux in the normal direction of the + // current sub control volume face + + // if geomechanical feedback on flow is taken into account the effective permeability is + // applied for the flux calculations + if (this->problem_().coupled() == true) { + Keff.mv(fluxVars.potentialGrad(phaseIdx), tmpVec); + } else { + fluxVars.intrinsicPermeability().mv( + fluxVars.potentialGrad(phaseIdx), tmpVec); + } + Scalar normalFlux = -(tmpVec * fluxVars.face().normal); + + // data attached to upstream and the downstream vertices + // of the current phase + const VolumeVariables &up = this->curVolVars_( + fluxVars.upstreamIdx(phaseIdx)); + const VolumeVariables &dn = this->curVolVars_( + fluxVars.downstreamIdx(phaseIdx)); + + // add advective flux of current phase + int eqIdx = (phaseIdx == wPhaseIdx) ? contiWEqIdx : contiNEqIdx; + flux[eqIdx] += normalFlux + * ((massUpwindWeight_) * up.density(phaseIdx) + * up.mobility(phaseIdx) + + (massUpwindWeight_) * dn.density(phaseIdx) + * dn.mobility(phaseIdx)); + + // if geomechanical feedback on flow is taken into account add the flux contribution + // of the displacement velocity + + if (this->problem_().coupled() == true) { + // use upwind displacement velocity to calculate phase transport (?) + flux[eqIdx] += up.effPorosity * up.saturation(phaseIdx) + * up.density(phaseIdx) * fluxVars.timeDerivUNormal(); + } + + } + } + + /*! + * \brief Calculate the source term of the equation + * + * \param q The source/sink in the SCV for each phase + * \param scvIdx The index of the SCV + * + */ + void computeSource(PrimaryVariables &q, int scvIdx) { + // retrieve the source term intrinsic to the problem + this->problem_().source(q, this->element_(), this->fvGeometry_(), + scvIdx); + } + +protected: + Implementation *asImp_() { + return static_cast<Implementation *>(this); + } + const Implementation *asImp_() const { + return static_cast<const Implementation *>(this); + } + +private: + Scalar massUpwindWeight_; +}; +} +#endif diff --git a/dumux/geomechanics/el2p/model.hh b/dumux/geomechanics/el2p/model.hh new file mode 100644 index 0000000000000000000000000000000000000000..3bfdc6be6ca46f1c5e163dcc625a99b5108f9988 --- /dev/null +++ b/dumux/geomechanics/el2p/model.hh @@ -0,0 +1,714 @@ +// -*- 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 Adaption of the fully implicit scheme to the two-phase linear elasticity model. +*/ + +#ifndef DUMUX_ELASTIC2P_MODEL_HH +#define DUMUX_ELASTIC2P_MODEL_HH + +#include <dune/pdelab/gridfunctionspace/interpolate.hh> +#include <dumux/common/eigenvalues.hh> +#include "properties.hh" + +namespace Dumux { + +namespace Properties { +NEW_PROP_TAG(InitialDisplacement); //!< The initial displacement function +NEW_PROP_TAG(InitialPressSat); //!< The initial pressure and saturation function +} + +/*! + * \ingroup ElTwoPBoxModel + * \brief Adaption of the fully implicit scheme to the two-phase linear elasticity model. + * + * This model implements a two-phase flow of compressible immiscible fluids \f$\alpha \in \{ w, n \}\f$. + * The deformation of the solid matrix is described with a quasi-stationary momentum balance equation. + * The influence of the pore fluid is accounted for through the effective stress concept (Biot 1941). + * The total stress acting on a rock is partially supported by the rock matrix and partially supported + * by the pore fluid. The effective stress represents the share of the total stress which is supported + * by the solid rock matrix and can be determined as a function of the strain according to Hooke's law. + * + * As an equation for the conservation of momentum within the fluid phases the standard multiphase Darcy's approach is used: + \f[ + v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \textbf{K} + \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} {\textbf g} \right) + \f] + * + * Gravity can be enabled or disabled via the property system. + * By inserting this into the continuity equation, one gets +\f[ + \frac{\partial \phi_{eff} \varrho_\alpha S_\alpha}{\partial t} + - \text{div} \left\{ \varrho_\alpha \frac{k_{r\alpha}}{\mu_\alpha} + \mathbf{K}_\text{eff} \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mathbf{g} \right) + - \phi_{eff} \varrho_\alpha S_\alpha \frac{\partial \mathbf{u}}{\partial t} + \right\} - q_\alpha = 0 \;, + \f] + * + * + * A quasi-stationary momentum balance equation is solved for the changes with respect to the initial conditions (Darcis 2012), note + * that this implementation assumes the soil mechanics sign convention (i.e. compressive stresses are negative): + \f[ + \text{div}\left( \boldsymbol{\Delta \sigma'}- \Delta p_{eff} \boldsymbol{I} \right) + \Delta \varrho_b {\textbf g} = 0 \;, + \f] + * with the effective stress: + \f[ + \boldsymbol{\sigma'} = 2\,G\,\boldsymbol{\epsilon} + \lambda \,\text{tr} (\boldsymbol{\epsilon}) \, \mathbf{I}. + \f] + * + * and the strain tensor \f$\boldsymbol{\epsilon}\f$ as a function of the solid displacement gradient \f$\textbf{grad} \mathbf{u}\f$: + \f[ + \boldsymbol{\epsilon} = \frac{1}{2} \, (\textbf{grad} \mathbf{u} + \textbf{grad}^T \mathbf{u}). + \f] + * + * Here, the rock mechanics sign convention is switch off which means compressive stresses are < 0 and tensile stresses are > 0. + * The rock mechanics sign convention can be switched on for the vtk output via the property system. + * + * The effective porosity and the effective permeability are calculated as a function of the solid displacement: + \f[ + \phi_{eff} = \frac{\phi_{init} + \text{div} \mathbf{u}}{1 + \text{div} \mathbf{u}} + \f] + \f[ + K_{eff} = K_{init} \text{exp}\left( 22.2(\phi_{eff}/\phi_{init} -1 )\right) + \f] + * The mass balance equations are discretized using a vertex-centered finite volume (box) + * or cell-centered finite volume scheme as spatial and the implicit Euler method as time discretization. + * The momentum balance equations are discretized using a standard Galerkin Finite Element method as + * spatial discretization scheme. + * + * + * The primary variables are the wetting phase pressure \f$p_w\f$, the nonwetting phase saturation \f$S_n\f$ and the solid + * displacement vector \f$\mathbf{u}\f$ (changes in solid displacement with respect to initial conditions). + */ +template<class TypeTag> +class ElTwoPModel: public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + numEq = GET_PROP_VALUE(TypeTag, NumEq), + nPhaseIdx = Indices::nPhaseIdx, + wPhaseIdx = Indices::wPhaseIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename Element::Geometry::JacobianInverseTransposed JacobianInverseTransposed; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; + typedef Dune::PDELab::LocalFunctionSpace<GridFunctionSpace> LocalFunctionSpace; + +public: + + /*! + * \brief Write the current solution to a restart file. + * + * \param outStream The output stream of one vertex for the restart file + * \param entity The Entity + * + * Due to the mixed discretization schemes which are combined via pdelab for this model + * the solution vector has a different form than in the pure box models + * it sorts the primary variables in the following way: + * p_vertex0 S_vertex0 p_vertex1 S_vertex1 p_vertex2 ....p_vertexN S_vertexN + * ux_vertex0 uy_vertex0 uz_vertex0 ux_vertex1 uy_vertex1 uz_vertex1 ... + * + * Therefore, the serializeEntity function has to be modified. + */ + template <class Entity> + void serializeEntity(std::ostream &outStream, + const Entity &entity) + { + // vertex index + int dofIdxGlobal = this->dofMapper().index(entity); + + // write phase state + if (!outStream.good()) { + DUNE_THROW(Dune::IOError, + "Could not serialize vertex " + << dofIdxGlobal); + } + int numScv = this->gridView().size(dim); + // get p and S entries for this vertex + for (int eqIdx = 0; eqIdx < numEq-dim; ++eqIdx) { + outStream << this->curSol().base()[dofIdxGlobal*(numEq-dim) + eqIdx][0]<<" "; + } + // get ux, uy, uz entries for this vertex + for (int j = 0; j< dim; ++j) + outStream << this->curSol().base()[numScv*(numEq-dim) + dofIdxGlobal*dim + j][0] <<" "; + + int vIdxGlobal = this->dofMapper().index(entity); + if (!outStream.good()) + DUNE_THROW(Dune::IOError, "Could not serialize vertex " << vIdxGlobal); + } + + /*! + * \brief Reads the current solution for a vertex from a restart + * file. + * + * \param inStream The input stream of one vertex from the restart file + * \param entity The Entity + * + * Due to the mixed discretization schemes which are combined via pdelab for this model + * the solution vector has a different form than in the pure box models + * it sorts the primary variables in the following way: + * p_vertex0 S_vertex0 p_vertex1 S_vertex1 p_vertex2 ....p_vertexN S_vertexN + * ux_vertex0 uy_vertex0 uz_vertex0 ux_vertex1 uy_vertex1 uz_vertex1 ... + * + * Therefore, the deserializeEntity function has to be modified. + */ + template<class Entity> + void deserializeEntity(std::istream &inStream, const Entity &entity) + { + int dofIdxGlobal = this->dofMapper().index(entity); + + if (!inStream.good()){ + DUNE_THROW(Dune::IOError, + "Could not deserialize vertex " + << dofIdxGlobal); + } + int numScv = this->gridView().size(dim); + for (int eqIdx = 0; eqIdx < numEq-dim; ++eqIdx) { + // read p and S entries for this vertex + inStream >> this->curSol().base()[dofIdxGlobal*(numEq-dim) + eqIdx][0];} + for (int j = 0; j< dim; ++j){ + // read ux, uy, uz entries for this vertex + inStream >> this->curSol().base()[numScv*(numEq-dim) + dofIdxGlobal*dim + j][0];} + } + + + /*! + * \brief \copybrief ImplicitModel::addOutputVtkFields + * + * Specialization for the ElOnePTwoCBoxModel, add one-phase two-component + * properties, solid displacement, stresses, effective properties and the + * process rank to the VTK writer. + */ + template<class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, MultiWriter &writer) { + // check whether compressive stresses are defined to be positive + // (rockMechanicsSignConvention_ == true) or negative + rockMechanicsSignConvention_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Vtk, RockMechanicsSignConvention); + + typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<double, dim> > VectorField; + + // create the required scalar and vector fields + unsigned numVertices = this->gridView_().size(dim); + unsigned numElements = this->gridView_().size(0); + + // create the required fields for vertex data + ScalarField &pw = *writer.allocateManagedBuffer(numVertices); + ScalarField &pn = *writer.allocateManagedBuffer(numVertices); + ScalarField &pc = *writer.allocateManagedBuffer(numVertices); + ScalarField &sw = *writer.allocateManagedBuffer(numVertices); + ScalarField &sn = *writer.allocateManagedBuffer(numVertices); + VectorField &displacement = *writer.template allocateManagedBuffer<Scalar, dim>(numVertices); + ScalarField &rhoW = *writer.allocateManagedBuffer(numVertices); + ScalarField &rhoN = *writer.allocateManagedBuffer(numVertices); + ScalarField &Te = *writer.allocateManagedBuffer(numVertices); + + // create the required fields for element data + // effective stresses + VectorField &deltaEffStressX = *writer.template allocateManagedBuffer<Scalar, + dim>(numElements); + VectorField &deltaEffStressY = *writer.template allocateManagedBuffer<Scalar, + dim>(numElements); + VectorField &deltaEffStressZ = *writer.template allocateManagedBuffer<Scalar, + dim>(numElements); + // total stresses + VectorField &totalStressX = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + VectorField &totalStressY = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + VectorField &totalStressZ = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + // initial stresses + VectorField &initStressX = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + VectorField &initStressY = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + VectorField &initStressZ = *writer.template allocateManagedBuffer< + Scalar, dim>(numElements); + // principal stresses + ScalarField &principalStress1 = *writer.allocateManagedBuffer( + numElements); + ScalarField &principalStress2 = *writer.allocateManagedBuffer( + numElements); + ScalarField &principalStress3 = *writer.allocateManagedBuffer( + numElements); + + + ScalarField &effKx = *writer.allocateManagedBuffer(numElements); + ScalarField &effPorosity = *writer.allocateManagedBuffer(numElements); + ScalarField &effectivePressure = *writer.allocateManagedBuffer(numElements); + ScalarField &deltaEffPressure = *writer.allocateManagedBuffer(numElements); + + + ScalarField &Pcrtens = *writer.allocateManagedBuffer(numElements); + ScalarField &Pcrshe = *writer.allocateManagedBuffer(numElements); + + // initialize cell stresses, cell-wise hydraulic parameters and cell pressure with zero + + + for (unsigned int eIdx = 0; eIdx < numElements; ++eIdx) { + deltaEffStressX[eIdx] = Scalar(0.0); + if (dim >= 2) + deltaEffStressY[eIdx] = Scalar(0.0); + if (dim >= 3) + deltaEffStressZ[eIdx] = Scalar(0.0); + + totalStressX[eIdx] = Scalar(0.0); + if (dim >= 2) + totalStressY[eIdx] = Scalar(0.0); + if (dim >= 3) + totalStressZ[eIdx] = Scalar(0.0); + + initStressX[eIdx] = Scalar(0.0); + if (dim >= 2) + initStressY[eIdx] = Scalar(0.0); + if (dim >= 3) + initStressZ[eIdx] = Scalar(0.0); + + principalStress1[eIdx] = Scalar(0.0); + if (dim >= 2) + principalStress2[eIdx] = Scalar(0.0); + if (dim >= 3) + principalStress3[eIdx] = Scalar(0.0); + + effPorosity[eIdx] = Scalar(0.0); + effKx[eIdx] = Scalar(0.0); + effectivePressure[eIdx] = Scalar(0.0); + deltaEffPressure[eIdx] = Scalar(0.0); + + Pcrtens[eIdx] = Scalar(0.0); + Pcrshe[eIdx] = Scalar(0.0); + } + + ScalarField &rank = *writer.allocateManagedBuffer(numElements); + + + FVElementGeometry fvGeometry; + ElementVolumeVariables elemVolVars; + + const GridFunctionSpace& gridFunctionSpace = this->problem_().model().jacobianAssembler().gridFunctionSpace(); + const typename GridFunctionSpace::Ordering& ordering = gridFunctionSpace.ordering(); + // initialize start and end of element iterator + // loop over all elements (cells) + for (const auto& element : Dune::elements(this->gridView_())) { + if(element.partitionType() == Dune::InteriorEntity) + { + + // get FE function spaces to calculate gradients (gradient data of momentum balance + // equation is not stored in fluxvars since it is not evaluated at box integration point) + // copy the values of the sol vector to the localFunctionSpace values of the current element + LocalFunctionSpace localFunctionSpace(gridFunctionSpace); + localFunctionSpace.bind(element); + std::vector<Scalar> values(localFunctionSpace.size()); + for (typename LocalFunctionSpace::Traits::IndexContainer::size_type k=0; k<localFunctionSpace.size(); ++k) + { + const typename GridFunctionSpace::Ordering::Traits::DOFIndex& di = localFunctionSpace.dofIndex(k); + typename GridFunctionSpace::Ordering::Traits::ContainerIndex ci; + ordering.mapIndex(di.view(),ci); + values[k] = sol[ci]; + } + + // local function space for solid displacement + typedef typename LocalFunctionSpace::template Child<1>::Type DisplacementLFS; + const DisplacementLFS& displacementLFS =localFunctionSpace.template child<1>(); + const unsigned int dispSize = displacementLFS.child(0).size(); + typedef typename DisplacementLFS::template Child<0>::Type ScalarDispLFS; + // further types required for gradient calculations + typedef typename ScalarDispLFS::Traits::FiniteElementType::Traits::LocalBasisType::Traits::JacobianType JacobianType_V; + typedef typename ScalarDispLFS::Traits::FiniteElementType::Traits::LocalBasisType::Traits::RangeFieldType RF; + + unsigned int eIdx = this->problem_().model().elementMapper().index(element); + rank[eIdx] = this->gridView_().comm().rank(); + + fvGeometry.update(this->gridView_(), element); + elemVolVars.update(this->problem_(), element, fvGeometry, false); + + // loop over all local vertices of the cell + int numScv = element.subEntities(dim); + + for (int scvIdx = 0; scvIdx < numScv; ++scvIdx) + { + unsigned int vIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); + + Te[vIdxGlobal] = elemVolVars[scvIdx].temperature(); + pw[vIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx); + pn[vIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx); + pc[vIdxGlobal] = elemVolVars[scvIdx].capillaryPressure(); + sw[vIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx); + sn[vIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx); + rhoW[vIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx); + rhoN[vIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx); + // the following lines are correct for rock mechanics sign convention + // but lead to a very counter-intuitive output therefore, they are commented. + // in case of rock mechanics sign convention solid displacement is + // defined to be negative if it points in positive coordinate direction +// if(rockMechanicsSignConvention_){ +// DimVector tmpDispl; +// tmpDispl = Scalar(0); +// tmpDispl -= elemVolVars[scvIdx].displacement(); +// displacement[vIdxGlobal] = tmpDispl; +// } +// +// else + displacement[vIdxGlobal] = elemVolVars[scvIdx].displacement(); + + double Keff; + double exponent; + exponent = 22.2 * (elemVolVars[scvIdx].effPorosity + / elemVolVars[scvIdx].porosity() - 1); + Keff = this->problem_().spatialParams().intrinsicPermeability( element, fvGeometry, scvIdx)[0][0]; + Keff *= exp(exponent); + effKx[eIdx] += Keff/ numScv; + effectivePressure[eIdx] += (pn[vIdxGlobal] * sn[vIdxGlobal] + + pw[vIdxGlobal] * sw[vIdxGlobal]) + / numScv; + effPorosity[eIdx] +=elemVolVars[scvIdx].effPorosity / numScv; + }; + + const auto geometry = element.geometry(); + + const GlobalPosition& cellCenter = geometry.center(); + const GlobalPosition& cellCenterLocal = geometry.local(cellCenter); + + deltaEffPressure[eIdx] = effectivePressure[eIdx] + this->problem().pInit(cellCenter, cellCenterLocal, element); + // determin changes in effective stress from current solution + // evaluate gradient of displacement shape functions + std::vector<JacobianType_V> vRefShapeGradient(dispSize); + displacementLFS.child(0).finiteElement().localBasis().evaluateJacobian(cellCenterLocal, vRefShapeGradient); + + // get jacobian to transform the gradient to physical element + const JacobianInverseTransposed jacInvT = geometry.jacobianInverseTransposed(cellCenterLocal); + std::vector < Dune::FieldVector<RF, dim> > vShapeGradient(dispSize); + for (size_t i = 0; i < dispSize; i++) { + vShapeGradient[i] = 0.0; + jacInvT.umv(vRefShapeGradient[i][0], vShapeGradient[i]); + } + // calculate gradient of current displacement + typedef Dune::FieldMatrix<RF, dim, dim> DimMatrix; + DimMatrix uGradient(0.0); + for (int coordDir = 0; coordDir < dim; ++coordDir) { + const ScalarDispLFS & scalarDispLFS = displacementLFS.child(coordDir); + + for (size_t i = 0; i < scalarDispLFS.size(); i++) + uGradient[coordDir].axpy(values[scalarDispLFS.localIndex(i)],vShapeGradient[i]); + } + + const Dune::FieldVector<Scalar, 2> lameParams = this->problem_().spatialParams().lameParams(element,fvGeometry, 0); + const Scalar lambda = lameParams[0]; + const Scalar mu = lameParams[1]; + + // calculate strain tensor + Dune::FieldMatrix<RF, dim, dim> epsilon; + for (int i = 0; i < dim; ++i) + for (int j = 0; j < dim; ++j) + epsilon[i][j] = 0.5 * (uGradient[i][j] + uGradient[j][i]); + + RF traceEpsilon = 0; + for (int i = 0; i < dim; ++i) + traceEpsilon += epsilon[i][i]; + + // calculate effective stress tensor + Dune::FieldMatrix<RF, dim, dim> sigma(0.0); + for (int i = 0; i < dim; ++i) { + sigma[i][i] = lambda * traceEpsilon; + for (int j = 0; j < dim; ++j) + sigma[i][j] += 2.0 * mu * epsilon[i][j]; + } + + // in case of rock mechanics sign convention compressive stresses + // are defined to be positive + if(rockMechanicsSignConvention_){ + deltaEffStressX[eIdx] -= sigma[0]; + if (dim >= 2) { + deltaEffStressY[eIdx] -= sigma[1]; + } + if (dim >= 3) { + deltaEffStressZ[eIdx] -= sigma[2]; + } + } + else{ + deltaEffStressX[eIdx] = sigma[0]; + if (dim >= 2) { + deltaEffStressY[eIdx] = sigma[1]; + } + if (dim >= 3) { + deltaEffStressZ[eIdx] = sigma[2]; + } + } + + // retrieve prescribed initial stresses from problem file + DimVector tmpInitStress = this->problem_().initialStress(cellCenter, 0); + if(rockMechanicsSignConvention_){ + initStressX[eIdx][0] = tmpInitStress[0]; + if (dim >= 2) { + initStressY[eIdx][1] = tmpInitStress[1]; + } + if (dim >= 3) { + initStressZ[eIdx][2] = tmpInitStress[2]; + } + } + else{ + initStressX[eIdx][0] -= tmpInitStress[0]; + if (dim >= 2) { + initStressY[eIdx][1] -= tmpInitStress[1]; + } + if (dim >= 3) { + initStressZ[eIdx][2] -= tmpInitStress[2]; + } + } + + // calculate total stresses + // in case of rock mechanics sign convention compressive stresses + // are defined to be positive and total stress is calculated by adding the pore pressure + if(rockMechanicsSignConvention_){ + totalStressX[eIdx][0] = initStressX[eIdx][0] + deltaEffStressX[eIdx][0] + deltaEffPressure[eIdx]; + if (dim >= 2) { + totalStressX[eIdx][1] = initStressX[eIdx][1] + deltaEffStressX[eIdx][1]; + totalStressY[eIdx][0] = initStressY[eIdx][0] + deltaEffStressY[eIdx][0]; + totalStressY[eIdx][1] = initStressY[eIdx][1] + deltaEffStressY[eIdx][1] + deltaEffPressure[eIdx]; + } + if (dim >= 3) { + totalStressX[eIdx][2] = initStressX[eIdx][2] + deltaEffStressX[eIdx][2]; + totalStressY[eIdx][2] = initStressY[eIdx][2] + deltaEffStressY[eIdx][2]; + totalStressZ[eIdx][0] = initStressZ[eIdx][0] + deltaEffStressZ[eIdx][0]; + totalStressZ[eIdx][1] = initStressZ[eIdx][1] + deltaEffStressZ[eIdx][1]; + totalStressZ[eIdx][2] = initStressZ[eIdx][2] + deltaEffStressZ[eIdx][2] + deltaEffPressure[eIdx]; + } + } + else{ + totalStressX[eIdx][0] = initStressX[eIdx][0] + deltaEffStressX[eIdx][0] - deltaEffPressure[eIdx]; + if (dim >= 2) { + totalStressX[eIdx][1] = initStressX[eIdx][1] + deltaEffStressX[eIdx][1]; + totalStressY[eIdx][0] = initStressY[eIdx][0] + deltaEffStressY[eIdx][0]; + totalStressY[eIdx][1] = initStressY[eIdx][1] + deltaEffStressY[eIdx][1] - deltaEffPressure[eIdx]; + } + if (dim >= 3) { + totalStressX[eIdx][2] = initStressX[eIdx][2] + deltaEffStressX[eIdx][2]; + totalStressY[eIdx][2] = initStressY[eIdx][2] + deltaEffStressY[eIdx][2]; + totalStressZ[eIdx][0] = initStressZ[eIdx][0] + deltaEffStressZ[eIdx][0]; + totalStressZ[eIdx][1] = initStressZ[eIdx][1] + deltaEffStressZ[eIdx][1]; + totalStressZ[eIdx][2] = initStressZ[eIdx][2] + deltaEffStressZ[eIdx][2] - deltaEffPressure[eIdx]; + } + } + } + } + + // calculate principal stresses i.e. the eigenvalues of the total stress tensor + Scalar a1, a2, a3; + DimMatrix totalStress; + DimVector eigenValues; + + for (unsigned int eIdx = 0; eIdx < numElements; eIdx++) + { + eigenValues = Scalar(0); + totalStress = Scalar(0); + + totalStress[0] = totalStressX[eIdx]; + if (dim >= 2) + totalStress[1] = totalStressY[eIdx]; + if (dim >= 3) + totalStress[2] = totalStressZ[eIdx]; + + calculateEigenValues<dim>(eigenValues, totalStress); + + + for (int i = 0; i < dim; i++) + { + if (isnan(eigenValues[i])) + eigenValues[i] = 0.0; + } + + // sort principal stresses: principalStress1 >= principalStress2 >= principalStress3 + if (dim == 2) { + a1 = eigenValues[0]; + a2 = eigenValues[1]; + + if (a1 >= a2) { + principalStress1[eIdx] = a1; + principalStress2[eIdx] = a2; + } else { + principalStress1[eIdx] = a2; + principalStress2[eIdx] = a1; + } + } + + if (dim == 3) { + a1 = eigenValues[0]; + a2 = eigenValues[1]; + a3 = eigenValues[2]; + + if (a1 >= a2) { + if (a1 >= a3) { + principalStress1[eIdx] = a1; + if (a2 >= a3) { + principalStress2[eIdx] = a2; + principalStress3[eIdx] = a3; + } + else //a3 > a2 + { + principalStress2[eIdx] = a3; + principalStress3[eIdx] = a2; + } + } + else // a3 > a1 + { + principalStress1[eIdx] = a3; + principalStress2[eIdx] = a1; + principalStress3[eIdx] = a2; + } + } else // a2>a1 + { + if (a2 >= a3) { + principalStress1[eIdx] = a2; + if (a1 >= a3) { + principalStress2[eIdx] = a1; + principalStress3[eIdx] = a3; + } + else //a3>a1 + { + principalStress2[eIdx] = a3; + principalStress3[eIdx] = a1; + } + } + else //a3>a2 + { + principalStress1[eIdx] = a3; + principalStress2[eIdx] = a2; + principalStress3[eIdx] = a1; + } + } + } + Scalar taum = 0.0; + Scalar sigmam = 0.0; + Scalar Peff = effectivePressure[eIdx]; + + Scalar theta = M_PI / 6; + Scalar S0 = 0.0; + taum = (principalStress1[eIdx] - principalStress3[eIdx]) / 2; + sigmam = (principalStress1[eIdx] + principalStress3[eIdx]) / 2; + Scalar Psc = -fabs(taum) / sin(theta) + S0 * cos(theta) / sin(theta) + + sigmam; + // Pressure margins according to J. Rutqvist et al. / International Journal of Rock Mecahnics & Mining Sciences 45 (2008), 132-143 + Pcrtens[eIdx] = Peff - principalStress3[eIdx]; + Pcrshe[eIdx] = Peff - Psc; + + } + + writer.attachVertexData(Te, "T"); + writer.attachVertexData(pw, "pW"); + writer.attachVertexData(pn, "pN"); + writer.attachVertexData(pc, "pC"); + writer.attachVertexData(sw, "SW"); + writer.attachVertexData(sn, "SN"); + writer.attachVertexData(rhoW, "rhoW"); + writer.attachVertexData(rhoN, "rhoN"); + writer.attachVertexData(displacement, "u", dim); + + writer.attachCellData(deltaEffStressX, "effective stress changes X", dim); + if (dim >= 2) + writer.attachCellData(deltaEffStressY, "effective stress changes Y", dim); + if (dim >= 3) + writer.attachCellData(deltaEffStressZ, "effective stress changes Z", dim); + + writer.attachCellData(principalStress1, "principal stress 1"); + if (dim >= 2) + writer.attachCellData(principalStress2, "principal stress 2"); + if (dim >= 3) + writer.attachCellData(principalStress3, "principal stress 3"); + + writer.attachCellData(totalStressX, "total stresses X", dim); + if (dim >= 2) + writer.attachCellData(totalStressY, "total stresses Y", dim); + if (dim >= 3) + writer.attachCellData(totalStressZ, "total stresses Z", dim); + + writer.attachCellData(initStressX, "initial stresses X", dim); + if (dim >= 2) + writer.attachCellData(initStressY, "initial stresses Y", dim); + if (dim >= 3) + writer.attachCellData(initStressZ, "initial stresses Z", dim); + + writer.attachCellData(deltaEffPressure, "delta pEff"); + writer.attachCellData(effectivePressure, "effectivePressure"); + writer.attachCellData(Pcrtens, "Pcr_tensile"); + writer.attachCellData(Pcrshe, "Pcr_shear"); + writer.attachCellData(effKx, "effective Kxx"); + writer.attachCellData(effPorosity, "effective Porosity"); + + + } + + /*! + * \brief Applies the initial solution for all vertices of the grid. + */ + void applyInitialSolution_() { + typedef typename GET_PROP_TYPE(TypeTag, InitialPressSat) InitialPressSat; + InitialPressSat initialPressSat(this->problem_().gridView()); + std::cout << "el2pmodel calls: initialPressSat" << std::endl; + initialPressSat.setPressure(this->problem_().pInit()); + + typedef typename GET_PROP_TYPE(TypeTag, InitialDisplacement) InitialDisplacement; + InitialDisplacement initialDisplacement(this->problem_().gridView()); + + typedef Dune::PDELab::CompositeGridFunction<InitialPressSat, + InitialDisplacement> InitialSolution; + InitialSolution initialSolution(initialPressSat, initialDisplacement); + + int numDofs = this->jacobianAssembler().gridFunctionSpace().size(); + //this->curSol().resize(numDofs); + //this->prevSol().resize(numDofs); + std::cout << "numDofs = " << numDofs << std::endl; + + Dune::PDELab::interpolate(initialSolution, + this->jacobianAssembler().gridFunctionSpace(), this->curSol()); + Dune::PDELab::interpolate(initialSolution, + this->jacobianAssembler().gridFunctionSpace(), this->prevSol()); + } + + const Problem& problem() const { + return this->problem_(); + } + +private: + bool rockMechanicsSignConvention_; + +}; +} +#include "el2ppropertydefaults.hh" +#endif diff --git a/dumux/geomechanics/el2p/newtoncontroller.hh b/dumux/geomechanics/el2p/newtoncontroller.hh new file mode 100644 index 0000000000000000000000000000000000000000..9787b1a8aed73b549baf2b40c5ff364db82721cd --- /dev/null +++ b/dumux/geomechanics/el2p/newtoncontroller.hh @@ -0,0 +1,170 @@ +// -*- 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 An el2p specific controller for the newton solver. + * + * This controller 'knows' what a 'physically meaningful' solution is + * which allows the newton method to abort quicker if the solution is + * way out of bounds. + */ +#ifndef DUMUX_EL2P_NEWTON_CONTROLLER_HH +#define DUMUX_EL2P_NEWTON_CONTROLLER_HH + +#include <dumux/nonlinear/newtoncontroller.hh> + +namespace Dumux { + +template <class TypeTag> +class ElTwoPNewtonController : public NewtonController<TypeTag> +{ + typedef NewtonController<TypeTag> ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, NewtonController) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, NewtonMethod) NewtonMethod; + + typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, LinearSolver) LinearSolver; + +public: + /*! + * \brief Destructor + */ + ElTwoPNewtonController(const Problem &problem) + : ParentType(problem),linearSolver_(problem) + { + this->setTargetSteps(9); + this->setMaxSteps(18); + }; + + void newtonUpdateRelError(const SolutionVector &uOld, + const SolutionVector &deltaU) + { + // calculate the relative error as the maximum relative + // deflection in any degree of freedom. + this->shift_ = 0; + + for (int i = 0; i < int(uOld.base().size()); ++i) { + Scalar vertErr = std::abs(deltaU.base()[i]/(1.0 + std::abs((uOld.base()[i]) + uOld.base()[i] - deltaU.base()[i])/2)); + this->shift_ = std::max(this->shift_, vertErr); + } + + this->shift_ = this->gridView_().comm().max(this->shift_); + } + + void newtonUpdate(SolutionVector &uCurrentIter, + const SolutionVector &uLastIter, + const SolutionVector &deltaU) + { +// this->writeConvergence_(uLastIter, deltaU); + + newtonUpdateRelError(uLastIter, deltaU); + + uCurrentIter = uLastIter; + uCurrentIter -= deltaU; + +// printvector(std::cout, deltaU, "new solution", "row", 12, 1, 3); + } + + /*! + * \brief Solve the linear system of equations \f$\mathbf{A}x - b = 0\f$. + * + * Throws Dumux::NumericalProblem if the linear solver didn't + * converge. + * + * \param A The matrix of the linear system of equations + * \param x The vector which solves the linear system + * \param b The right hand side of the linear system + */ + void newtonSolveLinear(JacobianMatrix &A, + SolutionVector &x, + SolutionVector &b) + { + try { + if (this->numSteps_ == 0) + { + Scalar norm2 = b.base().two_norm2(); + if (this->gridView_().comm().size() > 1) + norm2 = this->gridView_().comm().sum(norm2); + + initialAbsoluteError_ = std::sqrt(norm2); + lastAbsoluteError_ = initialAbsoluteError_; + } + + int converged = linearSolver_.solve(A.base(), x.base(), b.base()); +// printvector(std::cout, x.base(), "x", "row", 5, 1, 5); +// printvector(std::cout, b.base(), "rhs", "row", 5, 1, 5); +// Dune::writeMatrixToMatlab(A.base(), "matrix.txt"); + + // make sure all processes converged + int convergedRemote = converged; + if (this->gridView_().comm().size() > 1) + convergedRemote = this->gridView_().comm().min(converged); + + if (!converged) { + DUNE_THROW(NumericalProblem, + "Linear solver did not converge"); + } + else if (!convergedRemote) { + DUNE_THROW(NumericalProblem, + "Linear solver did not converge on a remote process"); + } + } + catch (Dune::MatrixBlockError e) { + // make sure all processes converged + int converged = 0; + if (this->gridView_().comm().size() > 1) + converged = this->gridView_().comm().min(converged); + + Dumux::NumericalProblem p; + std::string msg; + std::ostringstream ms(msg); + ms << e.what() << "M=" << A.base()[e.r][e.c]; + p.message(ms.str()); + throw p; + } + catch (const Dune::Exception &e) { + // make sure all processes converged + int converged = 0; + if (this->gridView_().comm().size() > 1) + converged = this->gridView_().comm().min(converged); + + Dumux::NumericalProblem p; + p.message(e.what()); + throw p; + } + } + + // absolute errors and tolerance + Scalar absoluteError_; + Scalar lastAbsoluteError_; + Scalar initialAbsoluteError_; + Scalar absoluteTolerance_; + + // the linear solver + LinearSolver linearSolver_; + +}; +} + +#endif diff --git a/dumux/geomechanics/el2p/properties.hh b/dumux/geomechanics/el2p/properties.hh new file mode 100644 index 0000000000000000000000000000000000000000..97bf223c2879d18d512efb61e1f193cfbbd20f58 --- /dev/null +++ b/dumux/geomechanics/el2p/properties.hh @@ -0,0 +1,89 @@ +// -*- 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 Defines the properties required for the two phase linear-elastic model. + * + * This class inherits from the properties of the two-phase model and + * from the properties of the simple linear-elastic model + */ + +#ifndef DUMUX_ELASTIC2P_PROPERTIES_HH +#define DUMUX_ELASTIC2P_PROPERTIES_HH + +#include <dumux/implicit/box/properties.hh> +#include <dumux/porousmediumflow/2p/implicit/properties.hh> + +namespace Dumux +{ +//////////////////////////////// +// properties +//////////////////////////////// +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tag for the twophase model with a linear elastic matrix +NEW_TYPE_TAG(BoxElasticTwoP, INHERITS_FROM(BoxModel)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// +NEW_PROP_TAG(DisplacementGridFunctionSpace); //!< grid function space for the displacement +NEW_PROP_TAG(PressureGridFunctionSpace); //!< grid function space for the pressure, saturation, ... +NEW_PROP_TAG(GridOperatorSpace); //!< The grid operator space +NEW_PROP_TAG(GridOperator); //!< The grid operator space +NEW_PROP_TAG(PressureFEM); //!< FE space used for pressure, saturation, ... +NEW_PROP_TAG(DisplacementFEM); //!< FE space used for displacement + +//! Returns whether the output should be written according to +//! rock mechanics sign convention (compressive stresses > 0) +NEW_PROP_TAG(VtkRockMechanicsSignConvention); + +//! Specifies the grid function space used for sub-problems +NEW_PROP_TAG(GridFunctionSpace); + +//! Specifies the grid operator used for sub-problems +NEW_PROP_TAG(GridOperator); + +//! Specifies the grid operator space used for sub-problems +NEW_PROP_TAG(GridOperatorSpace); + +//! Specifies the type of the constraints +NEW_PROP_TAG(Constraints); + +//! Specifies the type of the constraints transformation +NEW_PROP_TAG(ConstraintsTrafo); + +//! Specifies the local finite element space +NEW_PROP_TAG(LocalFEMSpace); + +//! Specifies the local operator +NEW_PROP_TAG(LocalOperator); + +//! The type traits required for using the AMG backend +NEW_PROP_TAG(AmgTraits); +} + +} + +#endif diff --git a/dumux/geomechanics/el2p/propertydefaults.hh b/dumux/geomechanics/el2p/propertydefaults.hh new file mode 100644 index 0000000000000000000000000000000000000000..aa4b8e157f700f755e32a1e0155cab42407c038a --- /dev/null +++ b/dumux/geomechanics/el2p/propertydefaults.hh @@ -0,0 +1,432 @@ +// -*- 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 Defines the properties required for the two phase linear-elastic model. + * + * This class inherits from the properties of the two-phase model and + * from the properties of the simple linear-elastic model + */ + +#ifndef DUMUX_ELASTIC2P_PROPERTY_DEFAULTS_HH +#define DUMUX_ELASTIC2P_PROPERTY_DEFAULTS_HH + +#include <dune/istl/schwarz.hh> +#include <dune/istl/novlpschwarz.hh> +#include <dune/istl/owneroverlapcopy.hh> +#include <dune/istl/paamg/pinfo.hh> +#include <dune/istl/preconditioners.hh> + +#include <dune/pdelab/backend/istlmatrixbackend.hh> +#include <dune/pdelab/gridfunctionspace/gridfunctionspace.hh> +#include <dune/pdelab/backend/istlvectorbackend.hh> +#include <dune/pdelab/common/function.hh> +#include <dune/pdelab/gridoperator/gridoperator.hh> +#include <dune/pdelab/finiteelementmap/qkfem.hh> + +#include "properties.hh" + +#include "model.hh" +#include "basemodel.hh" +#include "indices.hh" +#include "localresidual.hh" +#include "localjacobian.hh" +#include "fluxvariables.hh" +#include "elementvolumevariables.hh" +#include "volumevariables.hh" +#include "localoperator.hh" +#include "assembler.hh" +#include "newtoncontroller.hh" +#include "indices.hh" +#include <dumux/implicit/box/propertydefaults.hh> +#include <dumux/porousmediumflow/2p/implicit/propertydefaults.hh> +#include <dumux/linear/seqsolverbackend.hh> +#include <dumux/linear/amgbackend.hh> + +namespace Dumux +{ + +////////////////////////////////////////////////////////////////// +// Property defaults +////////////////////////////////////////////////////////////////// + +namespace Properties +{ +SET_PROP(BoxElasticTwoP, NumEq) //!< set the number of equations to dim + 2 +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + static const int dim = Grid::dimension; +public: + static const int value = dim + 2; +}; + +SET_INT_PROP(BoxElasticTwoP, NumPhases, 2); //!< The number of fluid phases in the elastic 2p model is 2 + +//! Use the elastic local jacobian operator for the two-phase linear-elastic model +SET_TYPE_PROP(BoxElasticTwoP, + LocalResidual, + ElTwoPLocalResidual<TypeTag>); + +//! the Model property +SET_TYPE_PROP(BoxElasticTwoP, Model, ElTwoPModel<TypeTag>); + +/*! + * \brief An array of secondary variable containers. + */ +SET_TYPE_PROP(BoxElasticTwoP, ElementVolumeVariables, Dumux::ElTwoPElementVolumeVariables<TypeTag>); + +//! the VolumeVariables property +SET_TYPE_PROP(BoxElasticTwoP, VolumeVariables, ElTwoPVolumeVariables<TypeTag>); + +//! Set the default formulation to pWsN +SET_INT_PROP(BoxElasticTwoP, + Formulation, + 0); + +//! The indices required by the two-phase linear-elastic model + +SET_PROP(BoxElasticTwoP, Indices) +{ + typedef ElTwoPIndices<TypeTag> type; +}; + +//! The FluxVariables required by the two-phase linear-elastic model +SET_TYPE_PROP(BoxElasticTwoP, FluxVariables, ElTwoPFluxVariables<TypeTag>); + +//! the default upwind factor. Default 1.0, i.e. fully upwind... +SET_SCALAR_PROP(BoxElasticTwoP, ImplicitMassUpwindWeight, 1.0); + +//! weight for the upwind mobility in the velocity calculation +SET_SCALAR_PROP(BoxElasticTwoP, ImplicitMobilityUpwindWeight, 1.0); + +//! enable gravity by default +SET_BOOL_PROP(BoxElasticTwoP, ProblemEnableGravity, true); + + +//! Enable evaluation of shape function gradients at the sub-control volume center by default +// Used for the computation of the pressure gradients +SET_BOOL_PROP(BoxElasticTwoP, EvalGradientsAtSCVCenter, true); + +/*! + * \brief Set the property for the material parameters by extracting + * it from the material law. + */ +SET_PROP(BoxElasticTwoP, MaterialLawParams) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + +public: + typedef typename MaterialLaw::Params type; +}; + + +// use the SuperLU linear solver by default +#if HAVE_SUPERLU +SET_TYPE_PROP(BoxElasticTwoP, LinearSolver, Dumux::SuperLUBackend<TypeTag> ); +#else +#warning no SuperLU detected, defaulting to ILU0BiCGSTAB. For many problems, the el2p model requires a direct solver. +SET_TYPE_PROP(BoxElasticTwoP, LinearSolver, Dumux::ILU0BiCGSTABBackend<TypeTag> ); +#endif + +// set the grid operator +SET_PROP(BoxElasticTwoP, GridOperator) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, ConstraintsTrafo) ConstraintsTrafo; + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; + typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LocalOperator; + typedef typename Dune::PDELab::ISTLMatrixBackend MatrixBackend; + + enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; + +public: + + typedef Dune::PDELab::GridOperator<GridFunctionSpace, + GridFunctionSpace, + LocalOperator, + MatrixBackend, + Scalar, Scalar, Scalar, + ConstraintsTrafo, + ConstraintsTrafo, + true + > type; +}; + +SET_PROP(BoxElasticTwoP, JacobianMatrix) +{ +private: + //typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GFSU; + typedef typename GFSU::template ConstraintsContainer<Scalar>::Type CU; + //! The global assembler type + typedef Dune::PDELab::DefaultAssembler<GFSU,GFSU,CU,CU,true> Assembler; + + //! The type of the domain (solution). + typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Domain; + //! The type of the range (residual). + typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Range; + //! The type of the jacobian. + typedef typename Dune::PDELab::ISTLMatrixBackend MB; + typedef typename Dune::PDELab::BackendMatrixSelector<MB,Domain,Range,Scalar>::Type Jacobian; + + //! The local assembler type + typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LOP; + typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef Dune::PDELab::DefaultLocalAssembler<GridOperator,LOP,true> + LocalAssembler; + //! The grid operator traits + typedef Dune::PDELab::GridOperatorTraits + <GFSU,GFSU,MB,Scalar,Scalar,Scalar,CU,CU,Assembler,LocalAssembler> Traits; +public: + typedef typename Traits::Jacobian type; +}; + +SET_PROP(BoxElasticTwoP, SolutionVector) +{ +private: + //typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GFSU; + typedef typename GFSU::template ConstraintsContainer<Scalar>::Type CU; + //! The global assembler type + typedef Dune::PDELab::DefaultAssembler<GFSU,GFSU,CU,CU,true> Assembler; + + //! The type of the domain (solution). + typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Domain; + //! The type of the range (residual). + typedef typename Dune::PDELab::BackendVectorSelector<GFSU,Scalar>::Type Range; + //! The type of the jacobian. + typedef typename Dune::PDELab::ISTLMatrixBackend MB; + typedef typename Dune::PDELab::BackendMatrixSelector<MB,Domain,Range,Scalar>::Type Jacobian; + + //! The local assembler type + typedef typename GET_PROP_TYPE(TypeTag, LocalOperator) LOP; + typedef typename GET_PROP_TYPE(TypeTag, GridOperator) GridOperator; + typedef Dune::PDELab::DefaultLocalAssembler<GridOperator,LOP,true> + LocalAssembler; + //! The grid operator traits + typedef Dune::PDELab::GridOperatorTraits + <GFSU,GFSU,MB,Scalar,Scalar,Scalar,CU,CU,Assembler,LocalAssembler> Traits; +public: + typedef typename Traits::Domain type; +}; + +SET_PROP(BoxElasticTwoP, PressureGridFunctionSpace) +{private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, PressureFEM) FEM; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename Dune::PDELab::EntityBlockedOrderingTag OrderingTag; + typedef typename Dune::PDELab::ISTLVectorBackend<> VBE; + enum{numEq = GET_PROP_VALUE(TypeTag, NumEq), + dim = GridView::dimension}; +public: + typedef Dune::PDELab::NoConstraints Constraints; + + typedef Dune::PDELab::GridFunctionSpace<GridView, FEM, Constraints, VBE> + ScalarGridFunctionSpace; + + typedef Dune::PDELab::PowerGridFunctionSpace<ScalarGridFunctionSpace, numEq-dim, VBE, OrderingTag> + type; + + typedef typename type::template ConstraintsContainer<Scalar>::Type + ConstraintsTrafo; +}; + +SET_PROP(BoxElasticTwoP, DisplacementGridFunctionSpace) +{private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, DisplacementFEM) FEM; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename Dune::PDELab::EntityBlockedOrderingTag OrderingTag; + typedef typename Dune::PDELab::ISTLVectorBackend<> VBE; + enum{dim = GridView::dimension}; +public: + typedef Dune::PDELab::NoConstraints Constraints; + + typedef Dune::PDELab::GridFunctionSpace<GridView, FEM, Constraints, VBE> + ScalarGridFunctionSpace; + + typedef Dune::PDELab::PowerGridFunctionSpace<ScalarGridFunctionSpace, dim, VBE, OrderingTag> + type; + + typedef typename type::template ConstraintsContainer<Scalar>::Type + ConstraintsTrafo; +}; + +SET_PROP(BoxElasticTwoP, GridFunctionSpace) +{private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, PressureGridFunctionSpace) PressureGFS; + typedef typename GET_PROP_TYPE(TypeTag, DisplacementGridFunctionSpace) DisplacementGFS; + typedef typename Dune::PDELab::LexicographicOrderingTag OrderingTag; + typedef typename Dune::PDELab::ISTLVectorBackend<> VBE; +public: + typedef Dune::PDELab::NoConstraints Constraints; + + typedef void ScalarGridFunctionSpace; + + typedef Dune::PDELab::CompositeGridFunctionSpace<VBE, OrderingTag, PressureGFS, DisplacementGFS> type; + + typedef typename type::template ConstraintsContainer<Scalar>::Type + ConstraintsTrafo; +}; + +SET_PROP(BoxElasticTwoP, ConstraintsTrafo) +{private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridFunctionSpace) GridFunctionSpace; +public: + typedef typename GridFunctionSpace::template ConstraintsContainer<Scalar>::Type type; +}; + +// set the grid function space for the sub-models +SET_TYPE_PROP(BoxElasticTwoP, Constraints, Dune::PDELab::NoConstraints); + +SET_TYPE_PROP(BoxElasticTwoP, JacobianAssembler, Dumux::PDELab::El2PAssembler<TypeTag>); + +SET_PROP(BoxElasticTwoP, WettingPhase) +{ private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; +public: + typedef Dumux::LiquidPhase<Scalar, Dumux::NullComponent<Scalar> > type; +}; + +SET_PROP(BoxElasticTwoP, NonwettingPhase) +{ private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; +public: + typedef Dumux::LiquidPhase<Scalar, Dumux::NullComponent<Scalar> > type; +}; + +SET_PROP(BoxElasticTwoP, FluidSystem) +{ private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, WettingPhase) WettingPhase; + typedef typename GET_PROP_TYPE(TypeTag, NonwettingPhase) NonwettingPhase; + +public: + typedef Dumux::FluidSystems::TwoPImmiscible<Scalar, + WettingPhase, + NonwettingPhase> type; +}; + +SET_PROP(BoxElasticTwoP, FluidState) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; +public: + typedef ImmiscibleFluidState<Scalar, FluidSystem> type; +}; + +// enable jacobian matrix recycling by default +SET_BOOL_PROP(BoxElasticTwoP, ImplicitEnableJacobianRecycling, false); +// enable partial reassembling by default +SET_BOOL_PROP(BoxElasticTwoP, ImplicitEnablePartialReassemble, false); + +SET_TYPE_PROP(BoxElasticTwoP, NewtonController, ElTwoPNewtonController<TypeTag>); + +SET_PROP(BoxElasticTwoP, LocalOperator) +{ + typedef Dumux::PDELab::El2PLocalOperator<TypeTag> type; +}; + +//! use the local FEM space associated with cubes by default +SET_PROP(BoxElasticTwoP, LocalFEMSpace) +{ + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + +public: + typedef Dune::PDELab::QkLocalFiniteElementMap<GridView,Scalar,Scalar,1> type; +}; + +/*! + * \brief A vector of primary variables. + */ +SET_PROP(BoxElasticTwoP, PrimaryVariables) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + enum{numEq = GET_PROP_VALUE(TypeTag, NumEq)}; +public: + typedef Dune::FieldVector<Scalar, numEq> type; +}; + +template <class TypeTag, class MType, class VType, bool isParallel> +class ElasticTwoPSolverTraits +: public NonoverlappingSolverTraits<MType, VType, isParallel> +{ +public: + typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; +}; + +template <class TypeTag, class MType, class VType> +class ElasticTwoPSolverTraits<TypeTag, MType, VType, true> +: public NonoverlappingSolverTraits<MType, VType, true> +{ +public: + typedef MType JacobianMatrix; +}; + +//! define the traits for the AMGBackend +SET_PROP(BoxElasticTwoP, AmgTraits) +{ +public: + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + enum { dofCodim = Grid::dimension, + isNonOverlapping = true }; + enum { isParallel = Dune::Capabilities::canCommunicate<Grid, dofCodim>::v }; + + static const int numEq = isParallel ? GET_PROP_VALUE(TypeTag, NumEq) + : GET_PROP_TYPE(TypeTag, JacobianMatrix)::block_type::rows; + + typedef Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,numEq,numEq> > MType; + typedef Dune::BlockVector<Dune::FieldVector<Scalar,numEq> > VType; + typedef ElasticTwoPSolverTraits<TypeTag, MType, VType, isParallel> SolverTraits; + typedef typename SolverTraits::Comm Comm; + typedef typename SolverTraits::LinearOperator LinearOperator; + typedef typename SolverTraits::ScalarProduct ScalarProduct; + typedef typename SolverTraits::Smoother Smoother; + typedef typename SolverTraits::JacobianMatrix JacobianMatrix; +}; + +//! The local jacobian operator +SET_TYPE_PROP(BoxElasticTwoP, LocalJacobian, Dumux::ElTwoPLocalJacobian<TypeTag>); + +SET_TYPE_PROP(BoxElasticTwoP, BaseModel, ElTwoPBaseModel<TypeTag>); + +//! set number of equations of the mathematical model as default +SET_INT_PROP(BoxElasticTwoP, LinearSolverBlockSize, 1); + +// write the stress and displacement output according to rock mechanics sign convention (compressive stresses > 0) +SET_BOOL_PROP(BoxElasticTwoP, VtkRockMechanicsSignConvention, true); + +// \} +} +} + +#endif diff --git a/dumux/geomechanics/el2p/volumevariables.hh b/dumux/geomechanics/el2p/volumevariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..951609d6b3d831666ad5d374ca5ca2e889c880ba --- /dev/null +++ b/dumux/geomechanics/el2p/volumevariables.hh @@ -0,0 +1,174 @@ +// -*- 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 Quantities required by the two-phase linear-elastic model which + * are defined on a vertex. + */ +#ifndef DUMUX_ELASTIC2P_VOLUME_VARIABLES_HH +#define DUMUX_ELASTIC2P_VOLUME_VARIABLES_HH + +#include <dumux/porousmediumflow/2p/implicit/volumevariables.hh> + +#include "properties.hh" + +namespace Dumux { +/*! + * \ingroup ElTwoPModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are are constant within a + * finite volume in the two-phase linear-elastic model. + * + * This class inherits from the vertexdata of the two-phase + * model and from the vertexdata of the simple + * linear-elastic model + */ +template<class TypeTag> +class ElTwoPVolumeVariables: public TwoPVolumeVariables<TypeTag> { + + typedef TwoPVolumeVariables<TypeTag> TwoPBase; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + + enum { dim = GridView::dimension }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dim> DimVector; + +public: + /*! + * \copydoc ImplicitVolumeVariables::update + */ + void update(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx, + bool isOldSol) + { + TwoPBase::update(priVars, problem, element, fvGeometry, scvIdx, isOldSol); + primaryVars_ = priVars; + + for (int coordDir = 0; coordDir < dim; ++coordDir) + displacement_[coordDir] = priVars[Indices::u(coordDir)]; + + effFluidDensity_ = this->density(wPhaseIdx) * this->saturation(wPhaseIdx) + + this->density(nPhaseIdx) * this->saturation(nPhaseIdx); + + const Dune::FieldVector<Scalar, 2> &lameParams = + problem.spatialParams().lameParams(element, fvGeometry, scvIdx); + + lambda_ = lameParams[0]; + mu_ = lameParams[1]; + + rockDensity_ = problem.spatialParams().rockDensity(element, scvIdx); + } + + /*! + * \brief Return the vector of primary variables + */ + const PrimaryVariables &primaryVars() const + { return primaryVars_; } + + /*! + * \brief Return the vector of primary variables + */ + const Scalar &priVar(int idx) const + { return primaryVars_[idx]; } + + /*! + * \brief Sets the evaluation point used in the by the local jacobian. + */ + void setEvalPoint(const Implementation *ep) + { } + + /*! + * \brief Returns the effective effective fluid density within + * the control volume. + */ + Scalar effFluidDensity() const + { return effFluidDensity_; } + + + /*! + * \brief Returns the Lame parameter lambda within the control volume. + */ + Scalar lambda() const + { return lambda_; } + + /*! + * \brief Returns the Lame parameter mu within the control volume. + */ + Scalar mu() const + { return mu_; } + + /*! + * \brief Returns the rock density within the control volume. + */ + Scalar rockDensity() const + { return rockDensity_; } + + /*! + * \brief Returns the solid displacement in all space + * directions within the control volume. + */ + Scalar displacement(int dimIdx) const + { return displacement_[dimIdx]; } + + /*! + * \brief Returns the solid displacement vector + * within the control volume. + */ + DimVector displacement() const + { return displacement_; } + + mutable Scalar divU; + mutable Scalar effPorosity; + +protected: + Scalar effFluidDensity_; + PrimaryVariables primaryVars_, prevPrimaryVars_; + DimVector displacement_, prevDisplacement_; + Scalar lambda_; + Scalar mu_; + Scalar rockDensity_; + +private: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } +}; + +} + +#endif diff --git a/dumux/geomechanics/elastic/elasticfluxvariables.hh b/dumux/geomechanics/elastic/elasticfluxvariables.hh index 82e33989e0c9cabce11fd40a49647d7cbd8bdd25..ae4e878db31bf5e13f756bd26c881cdb2b0f746d 100644 --- a/dumux/geomechanics/elastic/elasticfluxvariables.hh +++ b/dumux/geomechanics/elastic/elasticfluxvariables.hh @@ -1,259 +1,8 @@ -// -*- 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 This file contains the data which is required to calculate the gradients - * over a face of a finite volume that are needed for the momentum balance - * of a linear-elastic solid. - * - * This means gradients of solid displacement vectors, strains and stresses at - * the integration point - * - * This class is also used as a base class for the one-phase and two-phase - * linear-elastic models. - */ -#ifndef DUMUX_ELASTIC_FLUX_VARIABLES_HH -#define DUMUX_ELASTIC_FLUX_VARIABLES_HH +#ifndef DUMUX_ELASTIC_FLUX_VARIABLES_HH_OLD +#define DUMUX_ELASTIC_FLUX_VARIABLES_HH_OLD -#include "elasticproperties.hh" +#warning this header is deprecated, use dumux/geomechanics/elastic/fluxvariables.hh instead -namespace Dumux -{ - -/*! - * \ingroup ElasticBoxModel - * \ingroup ImplicitFluxVariables - * \brief This template class contains the data which is required to - * calculate the gradients over a face of a finite volume for - * the linear elasticity model. - * - * This means gradients of solid displacement vectors, strains and stresses at - * the integration point - */ -template<class TypeTag> -class ElasticFluxVariablesBase -{ - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - enum { - dim = GridView::dimension - }; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; - -public: - /* - * \brief The constructor - * - * \param problem The problem - * \param element The finite element - * \param fvGeometry The finite-volume geometry in the fully implicit scheme - * \param fIdx The local index of the SCV (sub-control-volume) face - * \param elemVolVars The volume variables of the current element - * \param onBoundary A boolean variable to specify whether the flux variables - * are calculated for interior SCV faces or boundary faces, default=false - */ - ElasticFluxVariablesBase(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : fvElemGeom_(fvGeometry), faceIdx_(fIdx), onBoundary_(onBoundary) - { - gradU_ = Scalar(0); - gradUTransposed_ = Scalar(0); - epsilon_ = Scalar(0); - sigma_ = Scalar(0); - - lambda_ = 0.; - mu_ = 0.; - divU_ = 0.; - - calculateGradients_(problem, element, elemVolVars); - calculateStrain_(problem, element, elemVolVars); - calculateStress_(problem, element, elemVolVars); - }; - -public: - - /*! - * \brief Return a stress tensor component [Pa] at the integration point. - */ - Scalar sigma(int row, int col) const - { return sigma_[row][col]; } - - /*! - * \brief Return the stress tensor [Pa] at the integration point. - */ - DimMatrix sigma() const - { return sigma_; } - - /*! - * \brief Return the volumetric strain i.e. the divergence of the solid displacement - * vector at the integration point. - */ - Scalar divU() const - { return divU_; } - - /*! - * \brief Returns the Lame parameter lambda at integration point. - */ - Scalar lambda() const - { return lambda_; } - - /*! - * \brief Returns the Lame parameter mu at integration point. - */ - Scalar mu() const - { return mu_; } - - /*! - * \brief Returns the sub-control-volume face. - */ - const SCVFace &face() const - { return fvElemGeom_.subContVolFace[faceIdx_]; } - -protected: - /*! - * \brief Calculation of the solid displacement gradients. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateGradients_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - const VolumeVariables &volVarsI = elemVolVars[face().i]; - const VolumeVariables &volVarsJ = elemVolVars[face().j]; - - // calculate gradients - DimVector tmp(0.0); - for (int idx = 0; - idx < fvElemGeom_.numScv; - idx++) // loop over adjacent vertices - { - // FE gradient at vertex idx - const DimVector &feGrad = face().grad[idx]; - - // the displacement vector gradient - for (int coordIdx = 0; coordIdx < dim; ++coordIdx) { - tmp = feGrad; - tmp *= elemVolVars[idx].displacement(coordIdx); - gradU_[coordIdx] += tmp; - } - } - - // average the Lame parameters at integration point - // note: it still needs to be checked which mean (arithmetic, harmonic.. is appropriate - lambda_ = (volVarsI.lambda() + volVarsJ.lambda()) / 2.; - mu_ = (volVarsI.mu() + volVarsJ.mu()) / 2.; - - for(int col=0; col < dim; col++) - { - divU_ += gradU_[col][col]; - - for(int row=0; row<dim; row++) - gradUTransposed_[row][col] = gradU_[col][row]; - } - } - - /*! - * \brief Calculation of the strain tensor. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateStrain_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - // calculate the strain tensor - epsilon_ += gradU_; - epsilon_ += gradUTransposed_; - epsilon_ *= 0.5; - } - - /*! - * \brief Calculation of the stress tensor. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateStress_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - DimMatrix firstTerm(0.0), secondTerm(0.0); - - epsilonTimesIdentity_ = divU_; - - firstTerm += epsilon_; - firstTerm *= 2; - firstTerm *= mu_; - - for (int i = 0; i < dim; ++i) - secondTerm[i][i] += 1.0; - secondTerm *= lambda_; - secondTerm *= epsilonTimesIdentity_; - - // calculate the stress tensor - sigma_ += firstTerm; - sigma_ += secondTerm; - } - - const FVElementGeometry &fvElemGeom_; - const int faceIdx_; - const bool onBoundary_; - - // Lame parameter mu at the integration point - Scalar mu_; - // Lame parameter lambda at the integration point - Scalar lambda_; - // divergence of the solid displacement vector at the integration point - Scalar divU_; - // volumetric strain at the integration point - Scalar epsilonTimesIdentity_; - // gradient and transposed gradient of the solid displacement vector - // at the integration point - DimMatrix gradU_, gradUTransposed_; - // strain tensor at the integration point - DimMatrix epsilon_; - // stress tensor at the integration point - DimMatrix sigma_; - -}; - -} // end namespace +#include <dumux/geomechanics/elastic/fluxvariables.hh> #endif diff --git a/dumux/geomechanics/elastic/elasticindices.hh b/dumux/geomechanics/elastic/elasticindices.hh index 104db4ab08aa055d185d4999b250166e70547c84..ff5f5227c9ce957db97fbad72cfa99dfaa99f65d 100644 --- a/dumux/geomechanics/elastic/elasticindices.hh +++ b/dumux/geomechanics/elastic/elasticindices.hh @@ -1,65 +1,8 @@ -// -*- 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 Defines the primary variable and equation indices used by - * the linear elasticity model - */ -#ifndef DUMUX_ELASTIC_INDICES_HH -#define DUMUX_ELASTIC_INDICES_HH +#ifndef DUMUX_ELASTIC_INDICES_HH_OLD +#define DUMUX_ELASTIC_INDICES_HH_OLD -namespace Dumux -{ -// \{ +#warning this header is deprecated, use dumux/geomechanics/elastic/indices.hh instead -/*! - * \ingroup ElasticBoxModel - * \ingroup ImplicitIndices - * \brief The indices for the linear elasticity model. - */ -template <int PVOffset = 0> -struct ElasticIndices -{ - // returns the equation index for a given space direction - static int momentum(int dirIdx) - { - return PVOffset + dirIdx; - }; - - // returns the primary variable index for a given space direction - static int u(int dirIdx) - { - return PVOffset + dirIdx; - }; - - // Equation indices - static const int momentumXEqIdx = PVOffset + 0; - static const int momentumYEqIdx = PVOffset + 1; - static const int momentumZEqIdx = PVOffset + 2; - - // primary variable indices - static const int uxIdx = PVOffset + 0; - static const int uyIdx = PVOffset + 1; - static const int uzIdx = PVOffset + 2; -}; - -}// namespace Dumux +#include <dumux/geomechanics/elastic/indices.hh> #endif - diff --git a/dumux/geomechanics/elastic/elasticlocalresidual.hh b/dumux/geomechanics/elastic/elasticlocalresidual.hh index ef940c55196a3a93b16c56c3032b272334911d8e..e3eae2e1d3c7aa84c78398ff3ec063986ed59337 100644 --- a/dumux/geomechanics/elastic/elasticlocalresidual.hh +++ b/dumux/geomechanics/elastic/elasticlocalresidual.hh @@ -1,140 +1,8 @@ -// -*- 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 Element-wise calculation the local Jacobian for the - * linear elastic model in the fully implicit scheme. - */ -#ifndef DUMUX_ELASTIC_LOCAL_RESIDUAL_HH -#define DUMUX_ELASTIC_LOCAL_RESIDUAL_HH +#ifndef DUMUX_ELASTIC_LOCAL_RESIDUAL_HH_OLD +#define DUMUX_ELASTIC_LOCAL_RESIDUAL_HH_OLD -#include "elasticproperties.hh" +#warning this header is deprecated, use dumux/geomechanics/elastic/localresidual.hh instead -namespace Dumux -{ -/*! - * - * \ingroup ElasticBoxModel - * \ingroup ImplicitLocalResidual - * \brief Calculate the local Jacobian for the linear - * elasticity model - * - * This class is used to fill the gaps in BoxLocalResidual for - * the linear elasticity model. - */ -template<class TypeTag> -class ElasticLocalResidual : public GET_PROP_TYPE(TypeTag, BaseLocalResidual) -{ -protected: - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; +#include <dumux/geomechanics/elastic/localresidual.hh> - enum { dim = GridView::dimension }; - typedef Dune::FieldVector<Scalar, dim> DimVector; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - -public: - /*! - * \brief Evaluate the amount of all conservation quantities - * within a finite volume. - * - * \param storage The storage of a quantity in the sub-control volume - * \param scvIdx The index of the considered face of the sub-control volume - * \param usePrevSol Evaluate function with solution of current or previous time step - */ - void computeStorage(PrimaryVariables &storage, const int scvIdx, const bool usePrevSol) const - { - // quasistationary conditions assumed - storage = Scalar(0); - } - - /*! - * \brief Evaluate the stress across a face of a sub-control - * volume. - * - * \param flux The stress over the SCV (sub-control-volume) face - * \param fIdx The index of the considered face of the sub control volume - * \param onBoundary A boolean variable to specify whether the flux variables - * are calculated for interior SCV faces or boundary faces, default=false - */ - void computeFlux(PrimaryVariables &flux, const int fIdx, const bool onBoundary=false) const - { - flux = 0; - FluxVariables fluxVars(this->problem_(), - this->element_(), - this->fvGeometry_(), - fIdx, - this->curVolVars_(), - onBoundary); - - // get normal vector of current face - const DimVector &normal(this->fvGeometry_().subContVolFace[fIdx].normal); - DimVector tmp(0.0); - - // multiply stress tensor with normal vector of current face - fluxVars.sigma().mv(normal, tmp); - - for (int i=0; i < dim; ++i) - { - flux[Indices::momentum(i)] = tmp[i]; - } - } - - /*! - * \brief Calculate the source term of the equation - * \param source The source/sink in the SCV is the gravity term in the momentum balance - * \param scvIdx The index of the vertex of the sub control volume - * - */ - void computeSource(PrimaryVariables &source, const int scvIdx) - { - const ElementVolumeVariables &elemVolVars = this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[scvIdx]; - - this->problem_().solDependentSource(source, - this->element_(), - this->fvGeometry_(), - scvIdx, - this->curVolVars_()); - - DimVector tmp1(0.0); - // gravity term of the momentum balance - // gravity of solid matrix - tmp1 = this->problem_().gravity(); - tmp1 *= volVars.rockDensity(); - - for (int i = 0; i < dim; ++i) - { - source[Indices::momentum(i)] += tmp1[i]; - } - } - -}; - -} // end namespace Dumux - -#endif // DUMUX_ELASTIC_LOCAL_RESIDUAL_HH +#endif diff --git a/dumux/geomechanics/elastic/elasticmodel.hh b/dumux/geomechanics/elastic/elasticmodel.hh index d048c5720b42dd7aa885d5615abb2e9f313efa3d..59ea49c67b66c3b6dbe9ef44d9b9b678a103e29e 100644 --- a/dumux/geomechanics/elastic/elasticmodel.hh +++ b/dumux/geomechanics/elastic/elasticmodel.hh @@ -1,203 +1,8 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * See the file COPYING for full copying permissions. * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -/*! - * \file - * - * \brief Base class for all models which use the linear elasticity model. - * Adaption of the fully implicit scheme to the linear elasticity model. - */ -#ifndef DUMUX_ELASTIC_MODEL_HH -#define DUMUX_ELASTIC_MODEL_HH +#ifndef DUMUX_ELASTIC_MODEL_HH_OLD +#define DUMUX_ELASTIC_MODEL_HH_OLD -#include "elasticproperties.hh" +#warning this header is deprecated, use dumux/geomechanics/elastic/model.hh instead -namespace Dumux -{ +#include <dumux/geomechanics/elastic/model.hh> -/*! - * \ingroup ElasticBoxModel - * \brief Adaption of the fully implicit scheme to the linear elasticity model. - * - * This model implements a linear elastic solid using Hooke's law as - * stress-strain relation and a quasi-stationary momentum balance equation: - \f[ - \boldsymbol{\sigma} = 2\,G\,\boldsymbol{\epsilon} + \lambda \,\text{tr} (\boldsymbol{\epsilon}) \, \boldsymbol{I}. - \f] - * - * with the strain tensor \f$\boldsymbol{\epsilon}\f$ as a function of the solid displacement gradient \f$\textbf{grad} \boldsymbol{u}\f$: - \f[ - \boldsymbol{\epsilon} = \frac{1}{2} \, (\textbf{grad} \boldsymbol{u} + \textbf{grad}^T \boldsymbol{u}). - \f] - * - * Gravity can be enabled or disabled via the property system. - * By inserting this into the momentum balance equation, one gets - \f[ - \text{div} \boldsymbol{\sigma} + \varrho {\textbf g} = 0 \;, - \f] - * - * The equation is discretized using a vertex-centered finite volume (box) - * scheme as spatial discretization. - * - */ - -template<class TypeTag > -class ElasticModel : public GET_PROP_TYPE(TypeTag, BaseModel) -{ - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum { - dim = GridView::dimension - }; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - -public: - /*! - * \brief \copybrief ImplicitModel::addOutputVtkFields - * - * Specialization for the ElasticBoxModel, adding solid displacement, - * stresses and the process rank to the VTK writer. - */ - template <class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, MultiWriter &writer) - { - typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; - typedef Dune::BlockVector<Dune::FieldVector<Scalar, dim> > VectorField; - - // create the required scalar fields - unsigned numScv = this->gridView_().size(dim); - unsigned numElements = this->gridView_().size(0); - - ScalarField &ux = *writer.allocateManagedBuffer(numScv); - ScalarField &uy = *writer.allocateManagedBuffer(numScv); - ScalarField &uz = *writer.allocateManagedBuffer(numScv); - VectorField &sigmax = *writer.template allocateManagedBuffer<Scalar, dim>(numElements); - VectorField &sigmay = *writer.template allocateManagedBuffer<Scalar, dim>(numElements); - VectorField &sigmaz = *writer.template allocateManagedBuffer<Scalar, dim>(numElements); - - // initialize stress fields - for (unsigned int i = 0; i < numElements; ++i) - { - sigmax[i] = 0; - if (dim > 1) - { - sigmay[i] = 0; - } - if (dim > 2) - { - sigmaz[i] = 0; - } - } - - ScalarField &rank = *writer.allocateManagedBuffer(numElements); - - FVElementGeometry fvGeometry; - VolumeVariables volVars; - ElementBoundaryTypes elemBcTypes; - - for (const auto& element : Dune::elements(this->gridView_())) - { - if(element.partitionType() == Dune::InteriorEntity) - { - int eIdx = this->problem_().model().elementMapper().index(element); - rank[eIdx] = this->gridView_().comm().rank(); - - fvGeometry.update(this->gridView_(), element); - elemBcTypes.update(this->problem_(), element, fvGeometry); - - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int vIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); - - volVars.update(sol[vIdxGlobal], - this->problem_(), - element, - fvGeometry, - scvIdx, - false); - - ux[vIdxGlobal] = volVars.displacement(0); - if (dim >= 2) - uy[vIdxGlobal] = volVars.displacement(1); - if (dim >= 3) - uz[vIdxGlobal] = volVars.displacement(2); - }; - - // In the box method, the stress is evaluated on the FE-Grid. However, to get an - // average apparent stress for the cell, all contributing stresses have to be interpolated. - DimMatrix stress; - - ElementVolumeVariables elemVolVars; - elemVolVars.update(this->problem_(), - element, - fvGeometry, - false /* isOldSol? */); - - // loop over the faces - for (int fIdx = 0; fIdx < fvGeometry.numScvf; fIdx++) - { - stress = 0.0; - //prepare the flux calculations (set up and prepare geometry, FE gradients) - FluxVariables fluxVars(this->problem_(), - element, - fvGeometry, - fIdx, - elemVolVars); - - stress = fluxVars.sigma(); - stress /= fvGeometry.numScvf; - - // Add up stresses for each cell. - // Beware the sign convention applied here: compressive stresses are negative - sigmax[eIdx] += stress[0]; - if (dim >= 2) - { - sigmay[eIdx] += stress[1]; - } - if (dim == 3) - { - sigmaz[eIdx] += stress[2]; - } - } - } - } - - - writer.attachVertexData(ux, "ux"); - if (dim >= 2) - writer.attachVertexData(uy, "uy"); - if (dim == 3) - writer.attachVertexData(uz, "uz"); - writer.attachCellData(sigmax, "stress X", dim); - if (dim >= 2) - writer.attachCellData(sigmay, "stress Y", dim); - if (dim == 3) - writer.attachCellData(sigmaz, "stress Z", dim); - } -}; -} -#include "elasticpropertydefaults.hh" #endif diff --git a/dumux/geomechanics/elastic/elasticproperties.hh b/dumux/geomechanics/elastic/elasticproperties.hh index 009162cd6f9861f185bcffd491004018cad751d3..18f9fe581241afe0ae1c9ee45cecba5c87dc661c 100644 --- a/dumux/geomechanics/elastic/elasticproperties.hh +++ b/dumux/geomechanics/elastic/elasticproperties.hh @@ -1,57 +1,8 @@ -// -*- 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/>. * - *****************************************************************************/ -/*! - * \ingroup Properties - * \ingroup ImplicitProperties - * \ingroup ElasticBoxModel - * \file - * - * \brief Defines the properties required for the linear elasticity model. - */ +#ifndef DUMUX_ELASTIC_PROPERTIES_HH_OLD +#define DUMUX_ELASTIC_PROPERTIES_HH_OLD -#ifndef DUMUX_ELASTIC_PROPERTIES_HH -#define DUMUX_ELASTIC_PROPERTIES_HH +#warning this header is deprecated, use dumux/geomechanics/elastic/properties.hh instead -#include <dumux/implicit/box/properties.hh> - -namespace Dumux -{ -// \{ -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tags for the implicit model for elastic deformations of the medium -NEW_TYPE_TAG(BoxElastic, INHERITS_FROM(BoxModel)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// - -NEW_PROP_TAG(Indices); //!< Enumerations for the model -NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem -NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters -} - -} +#include <dumux/geomechanics/elastic/properties.hh> #endif - diff --git a/dumux/geomechanics/elastic/elasticpropertydefaults.hh b/dumux/geomechanics/elastic/elasticpropertydefaults.hh index 804d151d3183ddf2a9c576fbdacceb588ec035d9..28611246163f5df61802fdb213d2ab4c9f910e6b 100644 --- a/dumux/geomechanics/elastic/elasticpropertydefaults.hh +++ b/dumux/geomechanics/elastic/elasticpropertydefaults.hh @@ -1,85 +1,8 @@ -// -*- 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/>. * - *****************************************************************************/ -/*! - * \ingroup Properties - * \ingroup ImplicitProperties - * \ingroup ElasticBoxModel - * \file - * - * \brief Defines some default values for the properties of the - * linear elasticity model. - */ +#ifndef DUMUX_ELASTIC_PROPERTIES_DEFAULTS_HH_OLD +#define DUMUX_ELASTIC_PROPERTIES_DEFAULTS_HH_OLD +#warning this header is deprecated, use dumux/geomechanics/elastic/propertydefaults.hh instead -#ifndef DUMUX_ELASTIC_PROPERTIES_DEFAULTS_HH -#define DUMUX_ELASTIC_PROPERTIES_DEFAULTS_HH - -#include "elasticproperties.hh" - -#include "elasticmodel.hh" -#include "elasticlocalresidual.hh" -#include "elasticvolumevariables.hh" -#include "elasticfluxvariables.hh" -#include "elasticindices.hh" - - - -namespace Dumux -{ -// \{ -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Property values -////////////////////////////////////////////////////////////////// - -//!< set the number of equations to the space dimension of the problem -SET_PROP(BoxElastic, NumEq) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum{dim = GridView::dimension}; -public: - static const int value = dim; -}; - -//! Use the linear elasticity local residual function for the elasticity model -SET_TYPE_PROP(BoxElastic, - LocalResidual, - ElasticLocalResidual<TypeTag>); - -//! define the model -SET_TYPE_PROP(BoxElastic, Model, ElasticModel<TypeTag>); - -//! define the VolumeVariables -SET_TYPE_PROP(BoxElastic, VolumeVariables, ElasticVolumeVariablesBase<TypeTag>); - -//! define the FluxVariables -SET_TYPE_PROP(BoxElastic, FluxVariables, ElasticFluxVariablesBase<TypeTag>); - -//! Set the indices used by the linear elasticity model -SET_TYPE_PROP(BoxElastic, Indices, ElasticIndices<>); - -//! enable gravity by default -SET_BOOL_PROP(BoxElastic, ProblemEnableGravity, true); -} -} +#include <dumux/geomechanics/elastic/propertydefaults.hh> #endif - diff --git a/dumux/geomechanics/elastic/elasticvolumevariables.hh b/dumux/geomechanics/elastic/elasticvolumevariables.hh index 3db1ecc0ff7b70eb6cb6e3a349cf6244ef82bea2..468776bc8e40d65ad3da71a83458424a813c21f2 100644 --- a/dumux/geomechanics/elastic/elasticvolumevariables.hh +++ b/dumux/geomechanics/elastic/elasticvolumevariables.hh @@ -1,142 +1,8 @@ -// -*- 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 Quantities required by the linear elasticity box - * model defined on a vertex. - */ -#ifndef DUMUX_ELASTIC_VOLUME_VARIABLES_HH -#define DUMUX_ELASTIC_VOLUME_VARIABLES_HH +#ifndef DUMUX_ELASTIC_VOLUME_VARIABLES_HH_OLD +#define DUMUX_ELASTIC_VOLUME_VARIABLES_HH_OLD -#include <dumux/implicit/volumevariables.hh> +#warning this header is deprecated, use dumux/geomechanics/elastic/volumevariables.hh instead -#include "elasticproperties.hh" - -namespace Dumux -{ -/*! - * \ingroup ElasticBoxModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are constant within a - * finite volume in the linear elasticity model. - */ -template <class TypeTag> -class ElasticVolumeVariablesBase : public ImplicitVolumeVariables<TypeTag> -{ - typedef ImplicitVolumeVariables<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - enum{ - dim = GridView::dimension, - }; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar,dim> DimVector; - -public: - /*! - * \copydoc ImplicitVolumeVariables::update - */ - void update(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx, - const bool isOldSol) - { - ParentType::update(priVars, - problem, - element, - fvGeometry, - scvIdx, - isOldSol); - - primaryVars_ = priVars; - - for (int i = 0; i < dim; ++i) - displacement_[i] = priVars[Indices::u(i)]; - - // retrieve Lame parameters and rock density from spatialParams - const Dune::FieldVector<Scalar, 2> &lameParams = - problem.spatialParams().lameParams(element, fvGeometry, scvIdx); - lambda_ = lameParams[0]; - mu_ = lameParams[1]; - rockDensity_ = problem.spatialParams().rockDensity(element, scvIdx); - } - - /*! - * \brief Return the vector of primary variables - */ - const PrimaryVariables &primaryVars() const - { return primaryVars_; } - - /*! - * \brief Sets the evaluation point used in the by the local jacobian. - */ - void setEvalPoint(const Implementation *ep) - { } - - /*! - * \brief Return the Lame parameter lambda \f$\mathrm{[Pa]}\f$ within the control volume. - */ - Scalar lambda() const - { return lambda_; } - - /*! - * \brief Return the Lame parameter mu \f$\mathrm{[Pa]}\f$ within the control volume. - */ - Scalar mu() const - { return mu_; } - - /*! - * \brief Returns the rock density \f$\mathrm{[kg / m^3]}\f$ within the control volume . - */ - Scalar rockDensity() const - { return rockDensity_; } - - /*! - * \brief Returns the solid displacement \f$\mathrm{[m]}\f$ in space - * directions dimIdx within the control volume. - */ - Scalar displacement(int dimIdx) const - { return displacement_[dimIdx]; } - - /*! - * \brief Returns the solid displacement vector \f$\mathrm{[m]}\f$ - * within the control volume. - */ - const DimVector &displacement() const - { return displacement_; } - -protected: - PrimaryVariables primaryVars_; - DimVector displacement_; - Scalar lambda_; - Scalar mu_; - Scalar rockDensity_; -}; - -} +#include <dumux/geomechanics/elastic/volumevariables.hh> #endif diff --git a/dumux/geomechanics/elastic/fluxvariables.hh b/dumux/geomechanics/elastic/fluxvariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..ded512f201a8bbcb5e4b6d51a1e53572c0354ac4 --- /dev/null +++ b/dumux/geomechanics/elastic/fluxvariables.hh @@ -0,0 +1,259 @@ +// -*- 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 This file contains the data which is required to calculate the gradients + * over a face of a finite volume that are needed for the momentum balance + * of a linear-elastic solid. + * + * This means gradients of solid displacement vectors, strains and stresses at + * the integration point + * + * This class is also used as a base class for the one-phase and two-phase + * linear-elastic models. + */ +#ifndef DUMUX_ELASTIC_FLUX_VARIABLES_HH +#define DUMUX_ELASTIC_FLUX_VARIABLES_HH + +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup ElasticBoxModel + * \ingroup ImplicitFluxVariables + * \brief This template class contains the data which is required to + * calculate the gradients over a face of a finite volume for + * the linear elasticity model. + * + * This means gradients of solid displacement vectors, strains and stresses at + * the integration point + */ +template<class TypeTag> +class ElasticFluxVariablesBase +{ + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + enum { + dim = GridView::dimension + }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; + +public: + /* + * \brief The constructor + * + * \param problem The problem + * \param element The finite element + * \param fvGeometry The finite-volume geometry in the fully implicit scheme + * \param fIdx The local index of the SCV (sub-control-volume) face + * \param elemVolVars The volume variables of the current element + * \param onBoundary A boolean variable to specify whether the flux variables + * are calculated for interior SCV faces or boundary faces, default=false + */ + ElasticFluxVariablesBase(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : fvElemGeom_(fvGeometry), faceIdx_(fIdx), onBoundary_(onBoundary) + { + gradU_ = Scalar(0); + gradUTransposed_ = Scalar(0); + epsilon_ = Scalar(0); + sigma_ = Scalar(0); + + lambda_ = 0.; + mu_ = 0.; + divU_ = 0.; + + calculateGradients_(problem, element, elemVolVars); + calculateStrain_(problem, element, elemVolVars); + calculateStress_(problem, element, elemVolVars); + }; + +public: + + /*! + * \brief Return a stress tensor component [Pa] at the integration point. + */ + Scalar sigma(int row, int col) const + { return sigma_[row][col]; } + + /*! + * \brief Return the stress tensor [Pa] at the integration point. + */ + DimMatrix sigma() const + { return sigma_; } + + /*! + * \brief Return the volumetric strain i.e. the divergence of the solid displacement + * vector at the integration point. + */ + Scalar divU() const + { return divU_; } + + /*! + * \brief Returns the Lame parameter lambda at integration point. + */ + Scalar lambda() const + { return lambda_; } + + /*! + * \brief Returns the Lame parameter mu at integration point. + */ + Scalar mu() const + { return mu_; } + + /*! + * \brief Returns the sub-control-volume face. + */ + const SCVFace &face() const + { return fvElemGeom_.subContVolFace[faceIdx_]; } + +protected: + /*! + * \brief Calculation of the solid displacement gradients. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateGradients_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + const VolumeVariables &volVarsI = elemVolVars[face().i]; + const VolumeVariables &volVarsJ = elemVolVars[face().j]; + + // calculate gradients + DimVector tmp(0.0); + for (int idx = 0; + idx < fvElemGeom_.numScv; + idx++) // loop over adjacent vertices + { + // FE gradient at vertex idx + const DimVector &feGrad = face().grad[idx]; + + // the displacement vector gradient + for (int coordIdx = 0; coordIdx < dim; ++coordIdx) { + tmp = feGrad; + tmp *= elemVolVars[idx].displacement(coordIdx); + gradU_[coordIdx] += tmp; + } + } + + // average the Lame parameters at integration point + // note: it still needs to be checked which mean (arithmetic, harmonic.. is appropriate + lambda_ = (volVarsI.lambda() + volVarsJ.lambda()) / 2.; + mu_ = (volVarsI.mu() + volVarsJ.mu()) / 2.; + + for(int col=0; col < dim; col++) + { + divU_ += gradU_[col][col]; + + for(int row=0; row<dim; row++) + gradUTransposed_[row][col] = gradU_[col][row]; + } + } + + /*! + * \brief Calculation of the strain tensor. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateStrain_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + // calculate the strain tensor + epsilon_ += gradU_; + epsilon_ += gradUTransposed_; + epsilon_ *= 0.5; + } + + /*! + * \brief Calculation of the stress tensor. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateStress_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + DimMatrix firstTerm(0.0), secondTerm(0.0); + + epsilonTimesIdentity_ = divU_; + + firstTerm += epsilon_; + firstTerm *= 2; + firstTerm *= mu_; + + for (int i = 0; i < dim; ++i) + secondTerm[i][i] += 1.0; + secondTerm *= lambda_; + secondTerm *= epsilonTimesIdentity_; + + // calculate the stress tensor + sigma_ += firstTerm; + sigma_ += secondTerm; + } + + const FVElementGeometry &fvElemGeom_; + const int faceIdx_; + const bool onBoundary_; + + // Lame parameter mu at the integration point + Scalar mu_; + // Lame parameter lambda at the integration point + Scalar lambda_; + // divergence of the solid displacement vector at the integration point + Scalar divU_; + // volumetric strain at the integration point + Scalar epsilonTimesIdentity_; + // gradient and transposed gradient of the solid displacement vector + // at the integration point + DimMatrix gradU_, gradUTransposed_; + // strain tensor at the integration point + DimMatrix epsilon_; + // stress tensor at the integration point + DimMatrix sigma_; + +}; + +} // end namespace + +#endif diff --git a/dumux/geomechanics/elastic/indices.hh b/dumux/geomechanics/elastic/indices.hh new file mode 100644 index 0000000000000000000000000000000000000000..20c4f3ea5f62829ff5a73dfe65fa9cff674aef3b --- /dev/null +++ b/dumux/geomechanics/elastic/indices.hh @@ -0,0 +1,64 @@ +// -*- 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 Defines the primary variable and equation indices used by + * the linear elasticity model + */ +#ifndef DUMUX_ELASTIC_INDICES_HH +#define DUMUX_ELASTIC_INDICES_HH + +namespace Dumux +{ +// \{ + +/*! + * \ingroup ElasticBoxModel + * \ingroup ImplicitIndices + * \brief The indices for the linear elasticity model. + */ +template <int PVOffset = 0> +struct ElasticIndices +{ + // returns the equation index for a given space direction + static int momentum(int dirIdx) + { + return PVOffset + dirIdx; + }; + + // returns the primary variable index for a given space direction + static int u(int dirIdx) + { + return PVOffset + dirIdx; + }; + + // Equation indices + static const int momentumXEqIdx = PVOffset + 0; + static const int momentumYEqIdx = PVOffset + 1; + static const int momentumZEqIdx = PVOffset + 2; + + // primary variable indices + static const int uxIdx = PVOffset + 0; + static const int uyIdx = PVOffset + 1; + static const int uzIdx = PVOffset + 2; +}; + +}// namespace Dumux + +#endif diff --git a/dumux/geomechanics/elastic/localresidual.hh b/dumux/geomechanics/elastic/localresidual.hh new file mode 100644 index 0000000000000000000000000000000000000000..34688b0bad11b3a60e85678332d36fe85d4379f1 --- /dev/null +++ b/dumux/geomechanics/elastic/localresidual.hh @@ -0,0 +1,140 @@ +// -*- 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 Element-wise calculation the local Jacobian for the + * linear elastic model in the fully implicit scheme. + */ +#ifndef DUMUX_ELASTIC_LOCAL_RESIDUAL_HH +#define DUMUX_ELASTIC_LOCAL_RESIDUAL_HH + +#include "properties.hh" + +namespace Dumux +{ +/*! + * + * \ingroup ElasticBoxModel + * \ingroup ImplicitLocalResidual + * \brief Calculate the local Jacobian for the linear + * elasticity model + * + * This class is used to fill the gaps in BoxLocalResidual for + * the linear elasticity model. + */ +template<class TypeTag> +class ElasticLocalResidual : public GET_PROP_TYPE(TypeTag, BaseLocalResidual) +{ +protected: + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + enum { dim = GridView::dimension }; + typedef Dune::FieldVector<Scalar, dim> DimVector; + + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + +public: + /*! + * \brief Evaluate the amount of all conservation quantities + * within a finite volume. + * + * \param storage The storage of a quantity in the sub-control volume + * \param scvIdx The index of the considered face of the sub-control volume + * \param usePrevSol Evaluate function with solution of current or previous time step + */ + void computeStorage(PrimaryVariables &storage, const int scvIdx, const bool usePrevSol) const + { + // quasistationary conditions assumed + storage = Scalar(0); + } + + /*! + * \brief Evaluate the stress across a face of a sub-control + * volume. + * + * \param flux The stress over the SCV (sub-control-volume) face + * \param fIdx The index of the considered face of the sub control volume + * \param onBoundary A boolean variable to specify whether the flux variables + * are calculated for interior SCV faces or boundary faces, default=false + */ + void computeFlux(PrimaryVariables &flux, const int fIdx, const bool onBoundary=false) const + { + flux = 0; + FluxVariables fluxVars(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_(), + onBoundary); + + // get normal vector of current face + const DimVector &normal(this->fvGeometry_().subContVolFace[fIdx].normal); + DimVector tmp(0.0); + + // multiply stress tensor with normal vector of current face + fluxVars.sigma().mv(normal, tmp); + + for (int i=0; i < dim; ++i) + { + flux[Indices::momentum(i)] = tmp[i]; + } + } + + /*! + * \brief Calculate the source term of the equation + * \param source The source/sink in the SCV is the gravity term in the momentum balance + * \param scvIdx The index of the vertex of the sub control volume + * + */ + void computeSource(PrimaryVariables &source, const int scvIdx) + { + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[scvIdx]; + + this->problem_().solDependentSource(source, + this->element_(), + this->fvGeometry_(), + scvIdx, + this->curVolVars_()); + + DimVector tmp1(0.0); + // gravity term of the momentum balance + // gravity of solid matrix + tmp1 = this->problem_().gravity(); + tmp1 *= volVars.rockDensity(); + + for (int i = 0; i < dim; ++i) + { + source[Indices::momentum(i)] += tmp1[i]; + } + } + +}; + +} // end namespace Dumux + +#endif // DUMUX_ELASTIC_LOCAL_RESIDUAL_HH diff --git a/dumux/geomechanics/elastic/model.hh b/dumux/geomechanics/elastic/model.hh new file mode 100644 index 0000000000000000000000000000000000000000..96fdf270d994a40c467d7fc56153806b4d4324e6 --- /dev/null +++ b/dumux/geomechanics/elastic/model.hh @@ -0,0 +1,203 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * + * \brief Base class for all models which use the linear elasticity model. + * Adaption of the fully implicit scheme to the linear elasticity model. + */ +#ifndef DUMUX_ELASTIC_MODEL_HH +#define DUMUX_ELASTIC_MODEL_HH + +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup ElasticBoxModel + * \brief Adaption of the fully implicit scheme to the linear elasticity model. + * + * This model implements a linear elastic solid using Hooke's law as + * stress-strain relation and a quasi-stationary momentum balance equation: + \f[ + \boldsymbol{\sigma} = 2\,G\,\boldsymbol{\epsilon} + \lambda \,\text{tr} (\boldsymbol{\epsilon}) \, \boldsymbol{I}. + \f] + * + * with the strain tensor \f$\boldsymbol{\epsilon}\f$ as a function of the solid displacement gradient \f$\textbf{grad} \boldsymbol{u}\f$: + \f[ + \boldsymbol{\epsilon} = \frac{1}{2} \, (\textbf{grad} \boldsymbol{u} + \textbf{grad}^T \boldsymbol{u}). + \f] + * + * Gravity can be enabled or disabled via the property system. + * By inserting this into the momentum balance equation, one gets + \f[ + \text{div} \boldsymbol{\sigma} + \varrho {\textbf g} = 0 \;, + \f] + * + * The equation is discretized using a vertex-centered finite volume (box) + * scheme as spatial discretization. + * + */ + +template<class TypeTag > +class ElasticModel : public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { + dim = GridView::dimension + }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + +public: + /*! + * \brief \copybrief ImplicitModel::addOutputVtkFields + * + * Specialization for the ElasticBoxModel, adding solid displacement, + * stresses and the process rank to the VTK writer. + */ + template <class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, MultiWriter &writer) + { + typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<Scalar, dim> > VectorField; + + // create the required scalar fields + unsigned numScv = this->gridView_().size(dim); + unsigned numElements = this->gridView_().size(0); + + ScalarField &ux = *writer.allocateManagedBuffer(numScv); + ScalarField &uy = *writer.allocateManagedBuffer(numScv); + ScalarField &uz = *writer.allocateManagedBuffer(numScv); + VectorField &sigmax = *writer.template allocateManagedBuffer<Scalar, dim>(numElements); + VectorField &sigmay = *writer.template allocateManagedBuffer<Scalar, dim>(numElements); + VectorField &sigmaz = *writer.template allocateManagedBuffer<Scalar, dim>(numElements); + + // initialize stress fields + for (unsigned int i = 0; i < numElements; ++i) + { + sigmax[i] = 0; + if (dim > 1) + { + sigmay[i] = 0; + } + if (dim > 2) + { + sigmaz[i] = 0; + } + } + + ScalarField &rank = *writer.allocateManagedBuffer(numElements); + + FVElementGeometry fvGeometry; + VolumeVariables volVars; + ElementBoundaryTypes elemBcTypes; + + for (const auto& element : Dune::elements(this->gridView_())) + { + if(element.partitionType() == Dune::InteriorEntity) + { + int eIdx = this->problem_().model().elementMapper().index(element); + rank[eIdx] = this->gridView_().comm().rank(); + + fvGeometry.update(this->gridView_(), element); + elemBcTypes.update(this->problem_(), element, fvGeometry); + + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int vIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); + + volVars.update(sol[vIdxGlobal], + this->problem_(), + element, + fvGeometry, + scvIdx, + false); + + ux[vIdxGlobal] = volVars.displacement(0); + if (dim >= 2) + uy[vIdxGlobal] = volVars.displacement(1); + if (dim >= 3) + uz[vIdxGlobal] = volVars.displacement(2); + }; + + // In the box method, the stress is evaluated on the FE-Grid. However, to get an + // average apparent stress for the cell, all contributing stresses have to be interpolated. + DimMatrix stress; + + ElementVolumeVariables elemVolVars; + elemVolVars.update(this->problem_(), + element, + fvGeometry, + false /* isOldSol? */); + + // loop over the faces + for (int fIdx = 0; fIdx < fvGeometry.numScvf; fIdx++) + { + stress = 0.0; + //prepare the flux calculations (set up and prepare geometry, FE gradients) + FluxVariables fluxVars(this->problem_(), + element, + fvGeometry, + fIdx, + elemVolVars); + + stress = fluxVars.sigma(); + stress /= fvGeometry.numScvf; + + // Add up stresses for each cell. + // Beware the sign convention applied here: compressive stresses are negative + sigmax[eIdx] += stress[0]; + if (dim >= 2) + { + sigmay[eIdx] += stress[1]; + } + if (dim == 3) + { + sigmaz[eIdx] += stress[2]; + } + } + } + } + + + writer.attachVertexData(ux, "ux"); + if (dim >= 2) + writer.attachVertexData(uy, "uy"); + if (dim == 3) + writer.attachVertexData(uz, "uz"); + writer.attachCellData(sigmax, "stress X", dim); + if (dim >= 2) + writer.attachCellData(sigmay, "stress Y", dim); + if (dim == 3) + writer.attachCellData(sigmaz, "stress Z", dim); + } +}; +} +#include "propertydefaults.hh" +#endif diff --git a/dumux/geomechanics/elastic/properties.hh b/dumux/geomechanics/elastic/properties.hh new file mode 100644 index 0000000000000000000000000000000000000000..b51b424c93959ef8468a480b4da5579f77a7b517 --- /dev/null +++ b/dumux/geomechanics/elastic/properties.hh @@ -0,0 +1,56 @@ +// -*- 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/>. * + *****************************************************************************/ +/*! + * \ingroup Properties + * \ingroup ImplicitProperties + * \ingroup ElasticBoxModel + * \file + * + * \brief Defines the properties required for the linear elasticity model. + */ + +#ifndef DUMUX_ELASTIC_PROPERTIES_HH +#define DUMUX_ELASTIC_PROPERTIES_HH + +#include <dumux/implicit/box/properties.hh> + +namespace Dumux +{ +// \{ +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tags for the implicit model for elastic deformations of the medium +NEW_TYPE_TAG(BoxElastic, INHERITS_FROM(BoxModel)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +NEW_PROP_TAG(Indices); //!< Enumerations for the model +NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem +NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters +} + +} + +#endif diff --git a/dumux/geomechanics/elastic/propertydefaults.hh b/dumux/geomechanics/elastic/propertydefaults.hh new file mode 100644 index 0000000000000000000000000000000000000000..b7c1c3123f652ecc53b54b327e42286fe2983130 --- /dev/null +++ b/dumux/geomechanics/elastic/propertydefaults.hh @@ -0,0 +1,84 @@ +// -*- 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/>. * + *****************************************************************************/ +/*! + * \ingroup Properties + * \ingroup ImplicitProperties + * \ingroup ElasticBoxModel + * \file + * + * \brief Defines some default values for the properties of the + * linear elasticity model. + */ + + +#ifndef DUMUX_ELASTIC_PROPERTIES_DEFAULTS_HH +#define DUMUX_ELASTIC_PROPERTIES_DEFAULTS_HH + +#include "properties.hh" + +#include "model.hh" +#include "localresidual.hh" +#include "volumevariables.hh" +#include "fluxvariables.hh" +#include "indices.hh" + + + +namespace Dumux +{ +// \{ +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Property values +////////////////////////////////////////////////////////////////// + +//!< set the number of equations to the space dimension of the problem +SET_PROP(BoxElastic, NumEq) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum{dim = GridView::dimension}; +public: + static const int value = dim; +}; + +//! Use the linear elasticity local residual function for the elasticity model +SET_TYPE_PROP(BoxElastic, + LocalResidual, + ElasticLocalResidual<TypeTag>); + +//! define the model +SET_TYPE_PROP(BoxElastic, Model, ElasticModel<TypeTag>); + +//! define the VolumeVariables +SET_TYPE_PROP(BoxElastic, VolumeVariables, ElasticVolumeVariablesBase<TypeTag>); + +//! define the FluxVariables +SET_TYPE_PROP(BoxElastic, FluxVariables, ElasticFluxVariablesBase<TypeTag>); + +//! Set the indices used by the linear elasticity model +SET_TYPE_PROP(BoxElastic, Indices, ElasticIndices<>); + +//! enable gravity by default +SET_BOOL_PROP(BoxElastic, ProblemEnableGravity, true); +} +} + +#endif diff --git a/dumux/geomechanics/elastic/volumevariables.hh b/dumux/geomechanics/elastic/volumevariables.hh new file mode 100644 index 0000000000000000000000000000000000000000..1d1cf57490bab97d5897c0ec3c32a1363befa09b --- /dev/null +++ b/dumux/geomechanics/elastic/volumevariables.hh @@ -0,0 +1,142 @@ +// -*- 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 Quantities required by the linear elasticity box + * model defined on a vertex. + */ +#ifndef DUMUX_ELASTIC_VOLUME_VARIABLES_HH +#define DUMUX_ELASTIC_VOLUME_VARIABLES_HH + +#include <dumux/implicit/volumevariables.hh> + +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup ElasticBoxModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are constant within a + * finite volume in the linear elasticity model. + */ +template <class TypeTag> +class ElasticVolumeVariablesBase : public ImplicitVolumeVariables<TypeTag> +{ + typedef ImplicitVolumeVariables<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + enum{ + dim = GridView::dimension, + }; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar,dim> DimVector; + +public: + /*! + * \copydoc ImplicitVolumeVariables::update + */ + void update(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx, + const bool isOldSol) + { + ParentType::update(priVars, + problem, + element, + fvGeometry, + scvIdx, + isOldSol); + + primaryVars_ = priVars; + + for (int i = 0; i < dim; ++i) + displacement_[i] = priVars[Indices::u(i)]; + + // retrieve Lame parameters and rock density from spatialParams + const Dune::FieldVector<Scalar, 2> &lameParams = + problem.spatialParams().lameParams(element, fvGeometry, scvIdx); + lambda_ = lameParams[0]; + mu_ = lameParams[1]; + rockDensity_ = problem.spatialParams().rockDensity(element, scvIdx); + } + + /*! + * \brief Return the vector of primary variables + */ + const PrimaryVariables &primaryVars() const + { return primaryVars_; } + + /*! + * \brief Sets the evaluation point used in the by the local jacobian. + */ + void setEvalPoint(const Implementation *ep) + { } + + /*! + * \brief Return the Lame parameter lambda \f$\mathrm{[Pa]}\f$ within the control volume. + */ + Scalar lambda() const + { return lambda_; } + + /*! + * \brief Return the Lame parameter mu \f$\mathrm{[Pa]}\f$ within the control volume. + */ + Scalar mu() const + { return mu_; } + + /*! + * \brief Returns the rock density \f$\mathrm{[kg / m^3]}\f$ within the control volume . + */ + Scalar rockDensity() const + { return rockDensity_; } + + /*! + * \brief Returns the solid displacement \f$\mathrm{[m]}\f$ in space + * directions dimIdx within the control volume. + */ + Scalar displacement(int dimIdx) const + { return displacement_[dimIdx]; } + + /*! + * \brief Returns the solid displacement vector \f$\mathrm{[m]}\f$ + * within the control volume. + */ + const DimVector &displacement() const + { return displacement_; } + +protected: + PrimaryVariables primaryVars_; + DimVector displacement_; + Scalar lambda_; + Scalar mu_; + Scalar rockDensity_; +}; + +} + +#endif diff --git a/test/geomechanics/el1p2c/el1p2cproblem.hh b/test/geomechanics/el1p2c/el1p2cproblem.hh index 6f67c37c3c68caad613b6772be8bea4fa0405ca6..4a1e85b4adae91a1b6ce9322461a64c4c5d23948 100644 --- a/test/geomechanics/el1p2c/el1p2cproblem.hh +++ b/test/geomechanics/el1p2c/el1p2cproblem.hh @@ -31,7 +31,7 @@ #include <iostream> #include <dune/grid/yaspgrid.hh> -#include <dumux/geomechanics/el1p2c/el1p2cmodel.hh> +#include <dumux/geomechanics/el1p2c/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidsystems/h2on2liquidphasefluidsystem.hh> diff --git a/test/geomechanics/el2p/el2pproblem.hh b/test/geomechanics/el2p/el2pproblem.hh index 2465c843da87feae4a366a43584d9e33f3249cf6..e92b1900b11b0ceb67cd1714abf241c6e69c4b73 100644 --- a/test/geomechanics/el2p/el2pproblem.hh +++ b/test/geomechanics/el2p/el2pproblem.hh @@ -29,8 +29,8 @@ #include <dumux/material/fluidsystems/brineco2fluidsystem.hh> #include <dumux/porousmediumflow/implicit/problem.hh> -#include <dumux/geomechanics/el2p/el2pmodel.hh> -#include <dumux/geomechanics/el2p/el2pamgbackend.hh> +#include <dumux/geomechanics/el2p/model.hh> +#include <dumux/geomechanics/el2p/amgbackend.hh> #include "el2pco2tables.hh" #include "el2pspatialparams.hh" @@ -454,7 +454,7 @@ public: * \param values The boundary types for the conservation equations * \param globalPos The center of the finite volume which ought to be set. * - * This function is called directly from dumux/geomechanics/el2p/el2plocaloperator.hh + * This function is called directly from dumux/geomechanics/el2p/localoperator.hh * If it is renamed to boundaryTypesAtPos it should be adjusted there as well. */ void boundaryTypesAtPos(BoundaryTypes &values, const GlobalPosition& globalPos) const @@ -521,7 +521,7 @@ public: * \param values The dirichlet values for the primary variables * \param globalPos The center of the finite volume which ought to be set. * - * This function is called directly from dumux/geomechanics/el2p/el2plocaloperator.hh + * This function is called directly from dumux/geomechanics/el2p/localoperator.hh * If it is renamed to dirichletAtPos it should be adjusted there as well. */ void dirichletAtPos(PrimaryVariables &values, const GlobalPosition& globalPos) const @@ -537,7 +537,7 @@ public: * \f$ [ \textnormal{unit of conserved quantity} / (m^2 \cdot s )] \f$ * \param globalPos The position of the integration point of the boundary segment. * - * This function is called directly from dumux/geomechanics/el2p/el2plocaloperator.hh + * This function is called directly from dumux/geomechanics/el2p/localoperator.hh * If it is renamed to neumannAtPos it should be adjusted there as well. * For this method, the \a values parameter stores the mass flux * in normal direction of each phase. Negative values mean influx. @@ -676,8 +676,8 @@ public: * * Set initial conditions for solution of momentum balance equation * i.e. initialize solid displacement - * This function is called from dumux/geomechanics/el2p/el2pmodel.hh - * * This function is called from dumux/geomechanics/el2p/el2pmodel.hh. + * This function is called from dumux/geomechanics/el2p/model.hh + * * This function is called from dumux/geomechanics/el2p/model.hh. * * The primary variables are initialized two times: * 1. before the initialization run. @@ -727,7 +727,7 @@ public: * Set initial conditions for solution of the mass balance equations * i.e. initialize wetting phase pressure and nonwetting phase saturation * - * This function is called from dumux/geomechanics/el2p/el2pmodel.hh. + * This function is called from dumux/geomechanics/el2p/model.hh. * The primary variables are initialized two times: * 1. before the initialization run. * 2. at the start of the actual simulation applying pressure field @@ -826,7 +826,7 @@ public: * * \param pInit The pressure field vector defined in the problem class * - * This function is called from dumux/geomechanics/el2p/el2pmodel.hh. + * This function is called from dumux/geomechanics/el2p/model.hh. */ void setPressure(std::vector<Scalar> pInit) { diff --git a/test/geomechanics/el2p/el2pspatialparams.hh b/test/geomechanics/el2p/el2pspatialparams.hh index ce4608a6128cb40d54d65e5909dd87ac4172dc0e..8009ad9c142edfff864aefea12a980d0871573b3 100644 --- a/test/geomechanics/el2p/el2pspatialparams.hh +++ b/test/geomechanics/el2p/el2pspatialparams.hh @@ -30,7 +30,7 @@ #include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh> #include <dumux/material/fluidmatrixinteractions/2p/efftoabslaw.hh> -#include <dumux/geomechanics/el2p/el2pmodel.hh> +#include <dumux/geomechanics/el2p/model.hh> namespace Dumux { diff --git a/test/geomechanics/elastic/elasticmatrixproblem.hh b/test/geomechanics/elastic/elasticmatrixproblem.hh index 4da33e69d6b68b96d29a53ea220e41d689691b6f..db9111eceb72e035c80eff89c076b4360f0b07ac 100644 --- a/test/geomechanics/elastic/elasticmatrixproblem.hh +++ b/test/geomechanics/elastic/elasticmatrixproblem.hh @@ -26,7 +26,7 @@ #include <dune/grid/io/file/dgfparser/dgfyasp.hh> -#include <dumux/geomechanics/elastic/elasticmodel.hh> +#include <dumux/geomechanics/elastic/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include "elasticspatialparams.hh" diff --git a/test/geomechanics/elastic/elasticspatialparams.hh b/test/geomechanics/elastic/elasticspatialparams.hh index b6a1aeb6a173ee2673ade727c55c2a2fe8d7651d..11bff53d07550492d9eb8a073248a8ff6963eb91 100644 --- a/test/geomechanics/elastic/elasticspatialparams.hh +++ b/test/geomechanics/elastic/elasticspatialparams.hh @@ -24,7 +24,7 @@ #ifndef DUMUX_ELASTIC_SPATIAL_PARAMS_HH #define DUMUX_ELASTIC_SPATIAL_PARAMS_HH -#include <dumux/geomechanics/el2p/el2pproperties.hh> +#include <dumux/geomechanics/el2p/properties.hh> namespace Dumux {