From 2b21b18402945dad764b9370ea0ff1091c805bd0 Mon Sep 17 00:00:00 2001 From: Bernd Flemisch <bernd@iws.uni-stuttgart.de> Date: Wed, 20 Jan 2016 14:12:50 +0100 Subject: [PATCH] [folder structure] rename and move files from implicit/1p2c,2p2c,2pnc,2pncmin,3p3c, adapt includes --- .../el1p2c/el1p2cfluxvariables.hh | 2 +- dumux/geomechanics/el1p2c/el1p2cindices.hh | 2 +- dumux/geomechanics/el1p2c/el1p2cproperties.hh | 2 +- .../el1p2c/el1p2cvolumevariables.hh | 2 +- dumux/implicit/1p2c/1p2cfluxvariables.hh | 525 +-------- dumux/implicit/1p2c/1p2cindices.hh | 63 +- dumux/implicit/1p2c/1p2clocalresidual.hh | 265 +---- dumux/implicit/1p2c/1p2cmodel.hh | 194 +--- dumux/implicit/1p2c/1p2cproperties.hh | 82 +- dumux/implicit/1p2c/1p2cpropertydefaults.hh | 159 +-- dumux/implicit/1p2c/1p2cvolumevariables.hh | 287 +---- dumux/implicit/2p2c/2p2cfluxvariables.hh | 255 +---- dumux/implicit/2p2c/2p2cindices.hh | 145 +-- dumux/implicit/2p2c/2p2clocalresidual.hh | 507 +------- dumux/implicit/2p2c/2p2cmodel.hh | 725 +----------- dumux/implicit/2p2c/2p2cnewtoncontroller.hh | 104 +- dumux/implicit/2p2c/2p2cproperties.hh | 85 +- dumux/implicit/2p2c/2p2cpropertydefaults.hh | 232 +--- dumux/implicit/2p2c/2p2cvolumevariables.hh | 621 +--------- dumux/implicit/2pnc/2pncfluxvariables.hh | 415 +------ dumux/implicit/2pnc/2pncindices.hh | 80 +- dumux/implicit/2pnc/2pnclocalresidual.hh | 349 +----- dumux/implicit/2pnc/2pncmodel.hh | 741 +----------- dumux/implicit/2pnc/2pncnewtoncontroller.hh | 105 +- dumux/implicit/2pnc/2pncproperties.hh | 82 +- dumux/implicit/2pnc/2pncpropertydefaults.hh | 226 +--- dumux/implicit/2pnc/2pncvolumevariables.hh | 529 +-------- .../implicit/2pncmin/2pncminfluxvariables.hh | 162 +-- dumux/implicit/2pncmin/2pncminindices.hh | 48 +- .../implicit/2pncmin/2pncminlocalresidual.hh | 140 +-- dumux/implicit/2pncmin/2pncminmodel.hh | 551 +-------- dumux/implicit/2pncmin/2pncminproperties.hh | 65 +- .../2pncmin/2pncminpropertydefaults.hh | 143 +-- .../2pncmin/2pncminvolumevariables.hh | 549 +-------- dumux/implicit/3p3c/3p3cfluxvariables.hh | 386 +------ dumux/implicit/3p3c/3p3cindices.hh | 90 +- dumux/implicit/3p3c/3p3clocalresidual.hh | 238 +--- dumux/implicit/3p3c/3p3cmodel.hh | 1020 +---------------- dumux/implicit/3p3c/3p3cnewtoncontroller.hh | 86 +- dumux/implicit/3p3c/3p3cproperties.hh | 82 +- dumux/implicit/3p3c/3p3cpropertydefaults.hh | 211 +--- dumux/implicit/3p3c/3p3cvolumevariables.hh | 750 +----------- dumux/implicit/co2/co2model.hh | 2 +- dumux/implicit/co2/co2volumevariables.hh | 2 +- .../2p2cnicouplinglocalresidual.hh | 2 +- .../2cstokes2p2c/2cstokes2p2clocaloperator.hh | 2 +- .../2cstokes2p2c/2p2ccouplinglocalresidual.hh | 4 +- .../1p2c/implicit/fluxvariables.hh | 525 +++++++++ .../porousmediumflow/1p2c/implicit/indices.hh | 63 + .../1p2c/implicit/localresidual.hh | 265 +++++ dumux/porousmediumflow/1p2c/implicit/model.hh | 194 ++++ .../1p2c/implicit/properties.hh | 81 ++ .../1p2c/implicit/propertydefaults.hh | 158 +++ .../1p2c/implicit/volumevariables.hh | 287 +++++ .../2p2c/implicit/fluxvariables.hh | 255 +++++ .../porousmediumflow/2p2c/implicit/indices.hh | 145 +++ .../2p2c/implicit/localresidual.hh | 507 ++++++++ dumux/porousmediumflow/2p2c/implicit/model.hh | 725 ++++++++++++ .../2p2c/implicit/newtoncontroller.hh | 104 ++ .../2p2c/implicit/properties.hh | 85 ++ .../2p2c/implicit/propertydefaults.hh | 232 ++++ .../2p2c/implicit/volumevariables.hh | 621 ++++++++++ .../2pnc/implicit/fluxvariables.hh | 415 +++++++ .../porousmediumflow/2pnc/implicit/indices.hh | 80 ++ .../2pnc/implicit/localresidual.hh | 349 ++++++ dumux/porousmediumflow/2pnc/implicit/model.hh | 741 ++++++++++++ .../2pnc/implicit/newtoncontroller.hh | 105 ++ .../2pnc/implicit/properties.hh | 82 ++ .../2pnc/implicit/propertydefaults.hh | 225 ++++ .../2pnc/implicit/volumevariables.hh | 529 +++++++++ .../2pncmin/implicit/fluxvariables.hh | 162 +++ .../2pncmin/implicit/indices.hh | 48 + .../2pncmin/implicit/localresidual.hh | 140 +++ .../2pncmin/implicit/model.hh | 551 +++++++++ .../2pncmin/implicit/properties.hh | 65 ++ .../2pncmin/implicit/propertydefaults.hh | 143 +++ .../2pncmin/implicit/volumevariables.hh | 549 +++++++++ .../3p3c/implicit/fluxvariables.hh | 386 +++++++ .../porousmediumflow/3p3c/implicit/indices.hh | 90 ++ .../3p3c/implicit/localresidual.hh | 238 ++++ dumux/porousmediumflow/3p3c/implicit/model.hh | 1020 +++++++++++++++++ .../3p3c/implicit/newtoncontroller.hh | 86 ++ .../3p3c/implicit/properties.hh | 82 ++ .../3p3c/implicit/propertydefaults.hh | 210 ++++ .../3p3c/implicit/volumevariables.hh | 750 ++++++++++++ .../2p/thermalconductivityjohansenproblem.hh | 2 +- .../2p/thermalconductivitysomertonproblem.hh | 2 +- .../2p/thermalconductivityspatialparams.hh | 2 +- .../effectivediffusivityconstanttauproblem.hh | 2 +- ...ectivediffusivitymillingtonquirkproblem.hh | 2 +- .../effectivediffusivityspatialparams.hh | 2 +- .../2cnistokes2p2cni/2p2cnisubproblem.hh | 2 +- .../2cnizeroeq2p2cni/2p2cnisubproblem.hh | 2 +- .../2cstokes2p2c/2p2csubproblem.hh | 2 +- .../2czeroeq2p2c/2p2csubproblem.hh | 2 +- .../1p2c/implicit/1p2cniconductionproblem.hh | 2 +- .../1p2c/implicit/1p2cniconvectionproblem.hh | 2 +- .../1p2c/implicit/1p2coutflowproblem.hh | 2 +- .../2p2c/implicit/injectionproblem.hh | 2 +- .../2p2c/implicit/injectionspatialparams.hh | 2 +- .../2p2c/implicit/waterairproblem.hh | 2 +- .../2p2c/implicit/waterairspatialparams.hh | 2 +- .../2pnc/implicit/fuelcellproblem.hh | 2 +- .../2pnc/implicit/fuelcellspatialparams.hh | 2 +- .../2pncmin/implicit/dissolutionproblem.hh | 2 +- .../implicit/dissolutionspatialparams.hh | 2 +- .../3p/implicit/3pnispatialparams.hh | 2 +- .../implicit/infiltration3pspatialparams.hh | 2 +- .../3p3c/implicit/columnxylolproblem.hh | 2 +- .../3p3c/implicit/columnxylolspatialparams.hh | 2 +- .../3p3c/implicit/infiltrationproblem.hh | 2 +- .../implicit/infiltrationspatialparameters.hh | 2 +- .../3p3c/implicit/kuevetteproblem.hh | 2 +- .../3p3c/implicit/kuevettespatialparams.hh | 2 +- 114 files changed, 11484 insertions(+), 11184 deletions(-) create mode 100644 dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh create mode 100644 dumux/porousmediumflow/1p2c/implicit/indices.hh create mode 100644 dumux/porousmediumflow/1p2c/implicit/localresidual.hh create mode 100644 dumux/porousmediumflow/1p2c/implicit/model.hh create mode 100644 dumux/porousmediumflow/1p2c/implicit/properties.hh create mode 100644 dumux/porousmediumflow/1p2c/implicit/propertydefaults.hh create mode 100644 dumux/porousmediumflow/1p2c/implicit/volumevariables.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/fluxvariables.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/indices.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/localresidual.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/model.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/newtoncontroller.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/properties.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/propertydefaults.hh create mode 100644 dumux/porousmediumflow/2p2c/implicit/volumevariables.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/fluxvariables.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/indices.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/localresidual.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/model.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/newtoncontroller.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/properties.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/propertydefaults.hh create mode 100644 dumux/porousmediumflow/2pnc/implicit/volumevariables.hh create mode 100644 dumux/porousmediumflow/2pncmin/implicit/fluxvariables.hh create mode 100644 dumux/porousmediumflow/2pncmin/implicit/indices.hh create mode 100644 dumux/porousmediumflow/2pncmin/implicit/localresidual.hh create mode 100644 dumux/porousmediumflow/2pncmin/implicit/model.hh create mode 100644 dumux/porousmediumflow/2pncmin/implicit/properties.hh create mode 100644 dumux/porousmediumflow/2pncmin/implicit/propertydefaults.hh create mode 100644 dumux/porousmediumflow/2pncmin/implicit/volumevariables.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/fluxvariables.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/indices.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/localresidual.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/model.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/newtoncontroller.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/properties.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/propertydefaults.hh create mode 100644 dumux/porousmediumflow/3p3c/implicit/volumevariables.hh diff --git a/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh b/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh index f63352f585..29c4ac9a35 100644 --- a/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh +++ b/dumux/geomechanics/el1p2c/el1p2cfluxvariables.hh @@ -33,7 +33,7 @@ #define DUMUX_ELASTIC1P2C_FLUX_VARIABLES_HH #include <dumux/geomechanics/elastic/elasticfluxvariables.hh> -#include <dumux/implicit/1p2c/1p2cfluxvariables.hh> +#include <dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh> namespace Dumux { diff --git a/dumux/geomechanics/el1p2c/el1p2cindices.hh b/dumux/geomechanics/el1p2c/el1p2cindices.hh index 4d82313029..25346a73ee 100644 --- a/dumux/geomechanics/el1p2c/el1p2cindices.hh +++ b/dumux/geomechanics/el1p2c/el1p2cindices.hh @@ -27,7 +27,7 @@ #define DUMUX_ELASTIC1P2C_INDICES_HH #include <dumux/geomechanics/elastic/elasticindices.hh> -#include <dumux/implicit/1p2c/1p2cindices.hh> +#include <dumux/porousmediumflow/1p2c/implicit/indices.hh> namespace Dumux { diff --git a/dumux/geomechanics/el1p2c/el1p2cproperties.hh b/dumux/geomechanics/el1p2c/el1p2cproperties.hh index cb913fd953..735524c243 100644 --- a/dumux/geomechanics/el1p2c/el1p2cproperties.hh +++ b/dumux/geomechanics/el1p2c/el1p2cproperties.hh @@ -32,7 +32,7 @@ #ifndef DUMUX_ELASTIC1P2C_PROPERTIES_HH #define DUMUX_ELASTIC1P2C_PROPERTIES_HH -#include <dumux/implicit/1p2c/1p2cproperties.hh> +#include <dumux/porousmediumflow/1p2c/implicit/properties.hh> #include <dumux/geomechanics/elastic/elasticproperties.hh> diff --git a/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh b/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh index 8556e55a2b..b8d6017559 100644 --- a/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh +++ b/dumux/geomechanics/el1p2c/el1p2cvolumevariables.hh @@ -26,7 +26,7 @@ #define DUMUX_ELASTIC1P2C_VOLUME_VARIABLES_HH -#include <dumux/implicit/1p2c/1p2cvolumevariables.hh> +#include <dumux/porousmediumflow/1p2c/implicit/volumevariables.hh> #include <dumux/implicit/volumevariables.hh> #include "el1p2cproperties.hh" diff --git a/dumux/implicit/1p2c/1p2cfluxvariables.hh b/dumux/implicit/1p2c/1p2cfluxvariables.hh index 641d9db8ff..496b22b6c1 100644 --- a/dumux/implicit/1p2c/1p2cfluxvariables.hh +++ b/dumux/implicit/1p2c/1p2cfluxvariables.hh @@ -1,525 +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 - * all fluxes of fluid phases over a face of a finite volume. - * - * This means pressure and mole-fraction gradients, phase densities at - * the integration point, etc. - * - */ -#ifndef DUMUX_1P2C_FLUX_VARIABLES_HH -#define DUMUX_1P2C_FLUX_VARIABLES_HH +#ifndef DUMUX_1P2C_FLUX_VARIABLES_HH_OLD +#define DUMUX_1P2C_FLUX_VARIABLES_HH_OLD -#include "1p2cproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh instead -#include <dumux/common/math.hh> -#include <dumux/common/valgrind.hh> - -namespace Dumux -{ - -/*! - * \ingroup OnePTwoCModel - * \ingroup ImplicitFluxVariables - * \brief This template class contains the data which is required to - * calculate the fluxes of the fluid phases over a face of a - * finite volume for the one-phase, two-component model. - * - * This means pressure and mole-fraction gradients, phase densities at - * the intergration point, etc. - */ -template <class TypeTag> -class OnePTwoCFluxVariables -{ - 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, SpatialParams) SpatialParams; - typedef typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel) EffectiveDiffusivityModel; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - transportCompIdx = Indices::transportCompIdx - }; - - 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 Dune::FieldVector<CoordScalar, dimWorld> GlobalPosition; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; - typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimWorldMatrix; - - 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 scvfIdx 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 - */ - OnePTwoCFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : fvGeometry_(fvGeometry), faceIdx_(fIdx), onBoundary_(onBoundary) - { - mobilityUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MobilityUpwindWeight); - - viscosity_ = Scalar(0); - molarDensity_ = Scalar(0); - density_ = Scalar(0); - potentialGrad_ = Scalar(0); - moleFractionGrad_ = Scalar(0); - - calculateGradients_(problem, element, elemVolVars); - calculateK_(problem, element, elemVolVars); - calculateVelocities_(problem, element, elemVolVars); - calculatePorousDiffCoeff_(problem, element, elemVolVars); - calculateDispersionTensor_(problem, element, elemVolVars); - }; - -public: - /*! - * \brief Return the pressure potential multiplied with the - * intrinsic permeability and the face normal which - * goes from vertex i to vertex j. - * - * Note that the length of the face's normal is the area of the - * phase, so this is not the actual velocity but the integral of - * the velocity over the face's area. Also note that the phase - * mobility is not yet included here since this would require a - * decision on the upwinding approach (which is done in the - * actual model). - */ - Scalar KmvpNormal() const - { return KmvpNormal_; } - - /*! - * \brief Return the pressure potential multiplied with the - * intrinsic permeability as vector (for velocity output). - */ - GlobalPosition Kmvp() const - { return Kmvp_; } - - /*! - * \brief The face of the current sub-control volume. This may be either - * an inner sub-control-volume face or a SCV face on the boundary. - */ - const SCVFace &face() const - { - if (onBoundary_) - return fvGeometry_.boundaryFace[faceIdx_]; - else - return fvGeometry_.subContVolFace[faceIdx_]; - } - - /*! - * \brief Return the intrinsic permeability tensor \f$\mathrm{[m^2]}\f$. - */ - const DimWorldMatrix &intrinsicPermeability() const - { return K_; } - - /*! - * \brief Return the dispersion tensor \f$\mathrm{[m^2/s]}\f$. - */ - const DimWorldMatrix &dispersionTensor() const - { return dispersionTensor_; } - - /*! - * \brief Return the pressure potential gradient \f$\mathrm{[Pa/m]}\f$. - */ - const GlobalPosition &potentialGrad() const - { return potentialGrad_; } - - - /*! - * \brief Return the mole-fraction gradient of a component in a phase \f$\mathrm{[mol/mol/m)]}\f$. - * - * \param compIdx The index of the considered component - */ - const GlobalPosition &moleFractionGrad(int compIdx) const - { - if (compIdx != 1) - { DUNE_THROW(Dune::InvalidStateException, - "The 1p2c model is supposed to need " - "only the concentration gradient of " - "the second component!"); } - return moleFractionGrad_; - }; - - /*! - * \brief The binary diffusion coefficient for each fluid phase in the porous medium \f$\mathrm{[m^2/s]}\f$. - */ - Scalar porousDiffCoeff() const - { - // TODO: tensorial porousDiffCoeff_usion coefficients - return porousDiffCoeff_; - }; - - /*! - * \brief Return viscosity \f$\mathrm{[Pa s]}\f$ of a phase at the integration - * point. - */ - Scalar viscosity() const - { return viscosity_;} - - /*! - * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ of a phase at the integration - * point. - */ - Scalar molarDensity() const - { return molarDensity_; } - - /*! - * \brief Return density \f$\mathrm{[kg/m^3]}\f$ of a phase at the integration - * point. - */ - Scalar density() const - { return density_; } - - /*! - * \brief Given the intrinsic permeability times the pressure - * potential gradient and SCV face normal for a phase, - * return the local index of the upstream control volume - * for a given phase. - * - * \param normalFlux The flux over a face of the sub-control volume - */ - int upstreamIdx(Scalar normalFlux) const - { return (normalFlux >= 0)?face().i:face().j; } - - /*! - * \brief Given the intrinsic permeability times the pressure - * potential gradient and SCV face normal for a phase, - * return the local index of the downstream control volume - * for a given phase. - * - * \param normalFlux The flux over a face of the sub-control volume - */ - int downstreamIdx(Scalar normalFlux) const - { return (normalFlux > 0)?face().j:face().i; } - - /*! - * \brief Return the local index of the upstream control volume - * for a given phase. - */ - int upstreamIdx() const - { return upstreamIdx_; } - - /*! - * \brief Return the local index of the downstream control volume - * for a given phase. - */ - int downstreamIdx() const - { return downstreamIdx_; } - - /*! - * \brief Return the local index of the upstream control volume - * for a given phase. - */ - int upstreamIdx(int phaseIdx) const - { return upstreamIdx_; } - - /*! - * \brief Return the local index of the downstream control volume - * for a given phase. - */ - int downstreamIdx(int phaseIdx) const - { return downstreamIdx_; } - - /*! - * \brief Return the volumetric flux over a face of a given phase. - * - * This is the calculated velocity multiplied by the unit normal - * and the area of the face. - * face().normal - * has already the magnitude of the area. - * - * \param phaseIdx index of the phase - */ - Scalar volumeFlux(const unsigned int phaseIdx) const - { - assert (phaseIdx == Indices::phaseIdx); - return volumeFlux_; - } - -protected: - - /*! - * \brief Calculation of the pressure and mole-/mass-fraction 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) - { - // loop over flux approximation points - for (unsigned int idx = 0; idx < face().numFap; idx++) - { - // FE gradient at vertex idx - const GlobalPosition &feGrad = face().grad[idx]; - - // index for the element volume variables - int volVarsIdx = face().fapIndices[idx]; - - // the pressure gradient - GlobalPosition tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].pressure(); - potentialGrad_ += tmp; - - // the mole-fraction gradient - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(transportCompIdx); - moleFractionGrad_ += tmp; - - // phase viscosity - viscosity_ += elemVolVars[volVarsIdx].viscosity()*face().shapeValue[idx]; - - //phase molar density - molarDensity_ += elemVolVars[volVarsIdx].molarDensity()*face().shapeValue[idx]; - - //phase density - density_ += elemVolVars[volVarsIdx].density()*face().shapeValue[idx]; - } - - - /////////////// - // correct the pressure gradients by the gravitational acceleration - /////////////// - if (GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity)) { - // calculate the phase density at the integration point. we - // only do this if the wetting phase is present in both cells - Scalar rhoI = elemVolVars[face().i].density(); - Scalar rhoJ = elemVolVars[face().j].density(); - Scalar density = (rhoI + rhoJ)/2; - - // ask for the gravitational acceleration at the given SCV face - GlobalPosition g(problem.gravityAtPos(face().ipGlobal)); - - // make it a force - g *= density; - - // calculate the final potential gradient - potentialGrad_ -= g; - } - } - - /*! - * \brief Calculation of the harmonic mean of the intrinsic permeability - * uses the meanK function in the boxspatialparameters.hh file in the folder - * material/spatialparameters - * - * \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) - { - const SpatialParams &sp = problem.spatialParams(); - if (GET_PROP_VALUE(TypeTag, ImplicitIsBox)) - { - sp.meanK(K_, - sp.intrinsicPermeability(element, - fvGeometry_, - face().i), - sp.intrinsicPermeability(element, - fvGeometry_, - face().j)); - } - else - { - const Element& elementI = fvGeometry_.neighbors[face().i]; - FVElementGeometry fvGeometryI; - fvGeometryI.subContVol[0].global = elementI.geometry().center(); - - const Element& elementJ = fvGeometry_.neighbors[face().j]; - FVElementGeometry fvGeometryJ; - fvGeometryJ.subContVol[0].global = elementJ.geometry().center(); - - sp.meanK(K_, - sp.intrinsicPermeability(elementI, fvGeometryI, 0), - sp.intrinsicPermeability(elementJ, fvGeometryJ, 0)); - } - } - - /*! - * \brief Calculation of the velocity normal to face using Darcy's law. - * Tensorial permeability is multiplied with the potential gradient and the face normal. - * Identify upstream node of face. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateVelocities_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - K_.mv(potentialGrad_, Kmvp_); - KmvpNormal_ = -(Kmvp_*face().normal); - - // set the upstream and downstream vertices - upstreamIdx_ = face().i; - downstreamIdx_ = face().j; - - if (KmvpNormal_ < 0) - { - std::swap(upstreamIdx_, - downstreamIdx_); - } - - volumeFlux_ = KmvpNormal_; - volumeFlux_ *= mobilityUpwindWeight_/elemVolVars[upstreamIdx_].viscosity() - + (1.0 - mobilityUpwindWeight_)/elemVolVars[downstreamIdx_].viscosity(); - } - /*! - * \brief Calculation of the effective 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 calculatePorousDiffCoeff_(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()); - - // -> harmonic mean - porousDiffCoeff_ = harmonicMean(diffCoeffI, diffCoeffJ); - } - - /*! - * \brief Calculation of the dispersion. - * - * \param problem The considered problem file - * \param element The considered element of the grid - * \param elemVolVars The parameters stored in the considered element - */ - void calculateDispersionTensor_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - const VolumeVariables &volVarsI = elemVolVars[face().i]; - const VolumeVariables &volVarsJ = elemVolVars[face().j]; - - //calculate dispersivity at the interface: [0]: alphaL = longitudinal disp. [m], [1] alphaT = transverse disp. [m] - Scalar dispersivity[2]; - dispersivity[0] = 0.5 * (volVarsI.dispersivity()[0] + volVarsJ.dispersivity()[0]); - dispersivity[1] = 0.5 * (volVarsI.dispersivity()[1] + volVarsJ.dispersivity()[1]); - - //calculate velocity at interface: v = -1/mu * vDarcy = -1/mu * K * grad(p) - GlobalPosition velocity; - Valgrind::CheckDefined(potentialGrad()); - Valgrind::CheckDefined(K_); - K_.mv(potentialGrad(), velocity); - velocity /= - 0.5 * (volVarsI.viscosity() + volVarsJ.viscosity()); - - //matrix multiplication of the velocity at the interface: vv^T - dispersionTensor_ = 0; - for (int i=0; i<dim; i++) - for (int j = 0; j<dim; j++) - dispersionTensor_[i][j] = velocity[i]*velocity[j]; - - //normalize velocity product --> vv^T/||v||, [m/s] - Scalar vNorm = velocity.two_norm(); - - dispersionTensor_ /= vNorm; - if (vNorm < 1e-20) - dispersionTensor_ = 0; - - //multiply with dispersivity difference: vv^T/||v||*(alphaL - alphaT), [m^2/s] --> alphaL = longitudinal disp., alphaT = transverse disp. - dispersionTensor_ *= (dispersivity[0] - dispersivity[1]); - - //add ||v||*alphaT to the main diagonal:vv^T/||v||*(alphaL - alphaT) + ||v||*alphaT, [m^2/s] - for (int i = 0; i<dim; i++) - dispersionTensor_[i][i] += vNorm*dispersivity[1]; - } - - const FVElementGeometry &fvGeometry_; - const int faceIdx_; - const bool onBoundary_; - - //! pressure potential gradient - GlobalPosition potentialGrad_; - //! mole-fraction gradient - GlobalPosition moleFractionGrad_; - //! the effective diffusion coefficent in the porous medium - Scalar porousDiffCoeff_; - - //! the dispersion tensor in the porous medium - DimWorldMatrix dispersionTensor_; - - //! the intrinsic permeability tensor - DimWorldMatrix K_; - // intrinsic permeability times pressure potential gradient - GlobalPosition Kmvp_; - // projected on the face normal - Scalar KmvpNormal_; - - // local index of the upwind vertex for each phase - int upstreamIdx_; - // local index of the downwind vertex for each phase - int downstreamIdx_; - - //! viscosity of the fluid at the integration point - Scalar viscosity_; - - //! molar densities of the fluid at the integration point - Scalar molarDensity_, density_; - - Scalar volumeFlux_; //!< Velocity multiplied with normal (magnitude=area) - Scalar mobilityUpwindWeight_; //!< Upwind weight for mobility. Set to one for full upstream weighting -}; - -} // end namespace +#include <dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh> #endif diff --git a/dumux/implicit/1p2c/1p2cindices.hh b/dumux/implicit/1p2c/1p2cindices.hh index 8286d90dab..6c9fbe18d8 100644 --- a/dumux/implicit/1p2c/1p2cindices.hh +++ b/dumux/implicit/1p2c/1p2cindices.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/>. * - *****************************************************************************/ -/*! - * \file - * \brief Defines the primary variable and equation indices used by - * the 1p2c model - */ +#ifndef DUMUX_1P2C_INDICES_HH_OLD +#define DUMUX_1P2C_INDICES_HH_OLD -#ifndef DUMUX_1P2C_INDICES_HH -#define DUMUX_1P2C_INDICES_HH +#warning this header is deprecated, use dumux/porousmediumflow/1p2c/implicit/indices.hh instead -#include "1p2cproperties.hh" - -namespace Dumux -{ -// \{ - -/*! - * \ingroup OnePTwoCModel - * \ingroup ImplicitIndices - * \brief The indices for the isothermal single-phase, two-component model. - */ -template <class TypeTag, int PVOffset = 0> -struct OnePTwoCIndices -{ - - //! Set the default phase used by the fluid system to the first one - static const int phaseIdx = GET_PROP_VALUE(TypeTag, PhaseIdx); - - //! Component indices - static const int phaseCompIdx = phaseIdx;//!< The index of the main component of the considered phase - //! The index of the transported (minor) component; ASSUMES phase indices of 0 and 1 - static const int transportCompIdx = (unsigned int)(1-phaseIdx); - - // Equation indices - static const int conti0EqIdx = PVOffset + 0; //!< continuity equation index - static const int transportEqIdx = PVOffset + 1; //!< transport equation index - - // primary variable indices - static const int pressureIdx = PVOffset + 0; //!< pressure - static const int massOrMoleFracIdx = PVOffset + 1; //!< mole fraction of the second component -}; - -// \} -} +#include <dumux/porousmediumflow/1p2c/implicit/indices.hh> #endif diff --git a/dumux/implicit/1p2c/1p2clocalresidual.hh b/dumux/implicit/1p2c/1p2clocalresidual.hh index a2436001a0..d5e9917cdd 100644 --- a/dumux/implicit/1p2c/1p2clocalresidual.hh +++ b/dumux/implicit/1p2c/1p2clocalresidual.hh @@ -1,265 +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 single-phase, - * two-component model in the fully implicit scheme. - */ +#ifndef DUMUX_ONEP_TWOC_LOCAL_RESIDUAL_HH_OLD +#define DUMUX_ONEP_TWOC_LOCAL_RESIDUAL_HH_OLD -#ifndef DUMUX_ONEP_TWOC_LOCAL_RESIDUAL_HH -#define DUMUX_ONEP_TWOC_LOCAL_RESIDUAL_HH +#warning this header is deprecated, use dumux/porousmediumflow/1p2c/implicit/localresidual.hh instead -#include "1p2cproperties.hh" - -namespace Dumux -{ -/*! - * - * \ingroup OnePTwoCModel - * \ingroup ImplicitLocalResidual - * \brief Calculate the local Jacobian for the single-phase, - * two-component model in the fully implicit scheme. - * - * This class is used to fill the gaps in BoxLocalResidual for the 1p2c flow and transport. - */ -template<class TypeTag> -class OnePTwoCLocalResidual : 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 }; - enum { dimWorld = GridView::dimensionworld }; - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - - 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, 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. - */ - OnePTwoCLocalResidual() - { - // 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); - }; - - /*! - * \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, const int scvIdx, const 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; - if(useMoles) // mole-fraction formulation - { - // storage term of continuity equation- molefractions - //careful: molarDensity changes with moleFrac! - storage[conti0EqIdx] += volVars.molarDensity()*volVars.porosity(); - // storage term of the transport equation - molefractions - storage[transportEqIdx] += - volVars.molarDensity()*volVars.moleFraction(transportCompIdx) * - volVars.porosity(); - } - else // mass-fraction formulation - { - // storage term of continuity equation - massfractions - storage[conti0EqIdx] += - volVars.density()*volVars.porosity(); - //storage term of the transport equation - massfractions - storage[transportEqIdx] += - volVars.density() * volVars.massFraction(transportCompIdx) * volVars.porosity(); - } - } - - /*! - * \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, const int fIdx, const bool onBoundary=false) const - { - flux = 0; - FluxVariables fluxVars(this->problem_(), - this->element_(), - this->fvGeometry_(), - fIdx, - this->curVolVars_(), - onBoundary); - - asImp_()->computeAdvectiveFlux(flux, fluxVars); - asImp_()->computeDiffusiveFlux(flux, fluxVars); - } - - /*! - * \brief Evaluate 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 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()); - - if(!useMoles) //mass-fraction formulation - { - // total mass flux - massfraction - //KmvpNormal is the Darcy velocity multiplied with the normal vector, calculated in 1p2cfluxvariables.hh - flux[conti0EqIdx] += - fluxVars.KmvpNormal() * - (( upwindWeight_)*up.density()/up.viscosity() - + - ((1 - upwindWeight_)*dn.density()/dn.viscosity())); - - // advective flux of the second component - massfraction - flux[transportEqIdx] += - fluxVars.KmvpNormal() * - (( upwindWeight_)*up.density() * up.massFraction(transportCompIdx)/up.viscosity() - + - (1 - upwindWeight_)*dn.density()*dn.massFraction(transportCompIdx)/dn.viscosity()); - } - else //mole-fraction formulation - { - // total mass flux - molefraction - //KmvpNormal is the Darcy velocity multiplied with the normal vector, calculated in 1p2cfluxvariables.hh - flux[conti0EqIdx] += - fluxVars.KmvpNormal() * - (( upwindWeight_)*up.molarDensity()/up.viscosity() - + - ((1 - upwindWeight_)*dn.molarDensity()/dn.viscosity())); - - // advective flux of the second component -molefraction - flux[transportEqIdx] += - fluxVars.KmvpNormal() * - (( upwindWeight_)*up.molarDensity() * up.moleFraction(transportCompIdx)/up.viscosity() - + - (1 - upwindWeight_)*dn.molarDensity() * dn.moleFraction(transportCompIdx)/dn.viscosity()); - } - - } - - /*! - * \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 SCV - */ - void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const - { - Scalar tmp(0); - - // diffusive flux of second component - if(useMoles) // mole-fraction formulation - { - // diffusive flux of the second component - molefraction - tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); - tmp *= fluxVars.porousDiffCoeff() * fluxVars.molarDensity(); - - // dispersive flux of second component - molefraction - GlobalPosition normalDisp; - fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); - tmp -= fluxVars.molarDensity()* - (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); - - flux[transportEqIdx] += tmp; - } - else // mass-fraction formulation - { - // diffusive flux of the second component - massfraction - tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); - tmp *= fluxVars.porousDiffCoeff() * fluxVars.molarDensity(); - - // dispersive flux of second component - massfraction - GlobalPosition normalDisp; - fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); - tmp -= fluxVars.molarDensity()* - (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); - - // convert it to a mass flux and add it - flux[transportEqIdx] += tmp * FluidSystem::molarMass(transportCompIdx); - } - } - - Implementation *asImp_() - { return static_cast<Implementation *> (this); } - const Implementation *asImp_() const - { return static_cast<const Implementation *> (this); } - -private: - Scalar upwindWeight_; -}; - -} +#include <dumux/porousmediumflow/1p2c/implicit/localresidual.hh> #endif diff --git a/dumux/implicit/1p2c/1p2cmodel.hh b/dumux/implicit/1p2c/1p2cmodel.hh index be109ff96e..b3f56c7ac8 100644 --- a/dumux/implicit/1p2c/1p2cmodel.hh +++ b/dumux/implicit/1p2c/1p2cmodel.hh @@ -1,194 +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 single-phase, - * two-component fully implicit model. - * Adaption of the fully implicit scheme to the one-phase two-component flow model. - */ +#ifndef DUMUX_ONEP_TWOC_MODEL_HH_OLD +#define DUMUX_ONEP_TWOC_MODEL_HH_OLD -#ifndef DUMUX_ONEP_TWOC_MODEL_HH -#define DUMUX_ONEP_TWOC_MODEL_HH +#warning this header is deprecated, use dumux/porousmediumflow/1p2c/implicit/model.hh instead -#include <dumux/porousmediumflow/implicit/velocityoutput.hh> -#include "1p2cproperties.hh" - -namespace Dumux -{ - -/*! - * \ingroup OnePTwoCModel - * \brief Adaption of the fully implicit scheme to the one-phase two-component flow model. - * - * This model implements a one-phase flow of a compressible fluid, that consists of two components, - * using a standard Darcy - * approach as the equation for the conservation of momentum: - \f[ - v = - \frac{\textbf K}{\mu} - \left(\textbf{grad}\, p - \varrho {\textbf g} \right) - \f] - * - * Gravity can be enabled or disabled via the property system. - * By inserting this into the continuity equation, one gets - \f[ - \phi\frac{\partial \varrho}{\partial t} - \text{div} \left\{ - \varrho \frac{\textbf K}{\mu} \left(\textbf{grad}\, p - \varrho {\textbf g} \right) - \right\} = q \;, - \f] - * - * The transport of the components \f$\kappa \in \{ w, a \}\f$ is described by the following equation: - \f[ - \phi \frac{ \partial \varrho X^\kappa}{\partial t} - - \text{div} \left\lbrace \varrho X^\kappa \frac{{\textbf K}}{\mu} \left( \textbf{grad}\, p - - \varrho {\textbf g} \right) - + \varrho D^\kappa_\text{pm} \frac{M^\kappa}{M_\alpha} \textbf{grad} x^\kappa \right\rbrace = q. - \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 model is able to use either mole or mass fractions. The property useMoles can be set to either true or false in the - * problem file. Make sure that the according units are used in the problem setup. useMoles is set to true by default. - * - * The primary variables are the pressure \f$p\f$ and the mole or mass fraction of dissolved component \f$x\f$. - */ - -template<class TypeTag > -class OnePTwoCModel : public GET_PROP_TYPE(TypeTag, BaseModel) -{ - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum { dim = GridView::dimension }; - enum { dimWorld = GridView::dimensionworld }; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { phaseIdx = Indices::phaseIdx }; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - -public: - /*! - * \brief \copybrief ImplicitModel::addOutputVtkFields - * - * Specialization for the OnePTwoCModel, adding pressure, - * mass and mole fractions, and the process rank to the VTK writer. - */ - template<class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, - MultiWriter &writer) - { - typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; - typedef Dune::BlockVector<Dune::FieldVector<double, dimWorld> > VectorField; - - // create the required scalar fields - unsigned numDofs = this->numDofs(); - ScalarField &pressure = *writer.allocateManagedBuffer(numDofs); - ScalarField &delp = *writer.allocateManagedBuffer(numDofs); - ScalarField &moleFraction0 = *writer.allocateManagedBuffer(numDofs); - ScalarField &moleFraction1 = *writer.allocateManagedBuffer(numDofs); - ScalarField &massFraction0 = *writer.allocateManagedBuffer(numDofs); - ScalarField &massFraction1 = *writer.allocateManagedBuffer(numDofs); - ScalarField &rho = *writer.allocateManagedBuffer(numDofs); - ScalarField &mu = *writer.allocateManagedBuffer(numDofs); - VectorField *velocity = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); - ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); - - if (velocityOutput.enableOutput()) - { - // initialize velocity field - for (unsigned int i = 0; i < numDofs; ++i) - { - (*velocity)[i] = Scalar(0); - } - } - - unsigned numElements = this->gridView_().size(0); - ScalarField &rank = *writer.allocateManagedBuffer(numElements); - - 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(); - - FVElementGeometry fvGeometry; - fvGeometry.update(this->gridView_(), element); - - ElementVolumeVariables elemVolVars; - elemVolVars.update(this->problem_(), - element, - fvGeometry, - false /* oldSol? */); - - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); - - pressure[dofIdxGlobal] = elemVolVars[scvIdx].pressure(); - delp[dofIdxGlobal] = elemVolVars[scvIdx].pressure() - 1e5; - moleFraction0[dofIdxGlobal] = elemVolVars[scvIdx].moleFraction(0); - moleFraction1[dofIdxGlobal] = elemVolVars[scvIdx].moleFraction(1); - massFraction0[dofIdxGlobal] = elemVolVars[scvIdx].massFraction(0); - massFraction1[dofIdxGlobal] = elemVolVars[scvIdx].massFraction(1); - rho[dofIdxGlobal] = elemVolVars[scvIdx].density(); - mu[dofIdxGlobal] = elemVolVars[scvIdx].viscosity(); - } - - // velocity output - velocityOutput.calculateVelocity(*velocity, elemVolVars, fvGeometry, element, phaseIdx); - } - } - - writer.attachDofData(pressure, "P", isBox); - writer.attachDofData(delp, "delp", isBox); - if (velocityOutput.enableOutput()) - { - writer.attachDofData(*velocity, "velocity", isBox, dim); - } - char nameMoleFraction0[42], nameMoleFraction1[42]; - snprintf(nameMoleFraction0, 42, "x_%s", FluidSystem::componentName(0)); - snprintf(nameMoleFraction1, 42, "x_%s", FluidSystem::componentName(1)); - writer.attachDofData(moleFraction0, nameMoleFraction0, isBox); - writer.attachDofData(moleFraction1, nameMoleFraction1, isBox); - - char nameMassFraction0[42], nameMassFraction1[42]; - snprintf(nameMassFraction0, 42, "X_%s", FluidSystem::componentName(0)); - snprintf(nameMassFraction1, 42, "X_%s", FluidSystem::componentName(1)); - writer.attachDofData(massFraction0, nameMassFraction0, isBox); - writer.attachDofData(massFraction1, nameMassFraction1, isBox); - writer.attachDofData(rho, "rho", isBox); - writer.attachDofData(mu, "mu", isBox); - writer.attachCellData(rank, "process rank"); - } -}; -} - -#include "1p2cpropertydefaults.hh" +#include <dumux/porousmediumflow/1p2c/implicit/model.hh> #endif diff --git a/dumux/implicit/1p2c/1p2cproperties.hh b/dumux/implicit/1p2c/1p2cproperties.hh index 5f511818b8..2d5a957ee5 100644 --- a/dumux/implicit/1p2c/1p2cproperties.hh +++ b/dumux/implicit/1p2c/1p2cproperties.hh @@ -1,82 +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 OnePTwoCModel - * \file - * - * \brief Defines the properties required for the single-phase, - * two-component fully implicit model. - */ +#ifndef DUMUX_1P2C_PROPERTIES_HH_OLD +#define DUMUX_1P2C_PROPERTIES_HH_OLD -#ifndef DUMUX_1P2C_PROPERTIES_HH -#define DUMUX_1P2C_PROPERTIES_HH +#warning this header is deprecated, use dumux/porousmediumflow/1p2c/implicit/properties.hh instead - -#include <dumux/implicit/box/properties.hh> -#include <dumux/implicit/cellcentered/properties.hh> -#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> - -namespace Dumux -{ -// \{ -namespace Properties -{ - -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tags for the implicit isothermal one-phase two-component problems -NEW_TYPE_TAG(OnePTwoC); -NEW_TYPE_TAG(BoxOnePTwoC, INHERITS_FROM(BoxModel, OnePTwoC)); -NEW_TYPE_TAG(CCOnePTwoC, INHERITS_FROM(CCModel, OnePTwoC)); - -//! The type tags for the corresponding non-isothermal problems -NEW_TYPE_TAG(OnePTwoCNI, INHERITS_FROM(OnePTwoC, NonIsothermal)); -NEW_TYPE_TAG(BoxOnePTwoCNI, INHERITS_FROM(BoxModel, OnePTwoCNI)); -NEW_TYPE_TAG(CCOnePTwoCNI, INHERITS_FROM(CCModel, OnePTwoCNI)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// - -NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system -NEW_PROP_TAG(PhaseIdx); //!< A phase index in to allow that a two-phase fluidsystem is used -NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system -NEW_PROP_TAG(Indices); //!< Enumerations for the model -NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters -NEW_PROP_TAG(EffectiveDiffusivityModel); //!< The employed model for the computation of the effective diffusivity -NEW_PROP_TAG(FluidSystem); //!< Type of the multi-component relations -NEW_PROP_TAG(FluidState); //!< Type of the fluid state to be used -NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The default value of the upwind weight -NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation -NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem -NEW_PROP_TAG(UseMoles); //!< Defines whether mole (true) or mass (false) fractions are used -NEW_PROP_TAG(Scaling); //!< Defines Scaling of the model -NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient -NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output - -} -// \} -} +#include <dumux/porousmediumflow/1p2c/implicit/properties.hh> #endif - diff --git a/dumux/implicit/1p2c/1p2cpropertydefaults.hh b/dumux/implicit/1p2c/1p2cpropertydefaults.hh index 7ce6e1294c..4561396de6 100644 --- a/dumux/implicit/1p2c/1p2cpropertydefaults.hh +++ b/dumux/implicit/1p2c/1p2cpropertydefaults.hh @@ -1,159 +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 OnePTwoCModel - * \file - * - * \brief Defines some default values for the properties of the the - * single-phase, two-component fully implicit model. - */ +#ifndef DUMUX_1P2C_PROPERTY_DEFAULTS_HH_OLD +#define DUMUX_1P2C_PROPERTY_DEFAULTS_HH_OLD -#ifndef DUMUX_1P2C_PROPERTY_DEFAULTS_HH -#define DUMUX_1P2C_PROPERTY_DEFAULTS_HH +#warning this header is deprecated, use dumux/porousmediumflow/1p2c/implicit/propertydefaults.hh instead -#include "1p2cproperties.hh" -#include "1p2cmodel.hh" -#include "1p2clocalresidual.hh" -#include "1p2cvolumevariables.hh" -#include "1p2cfluxvariables.hh" -#include "1p2cindices.hh" - -#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> -#include <dumux/material/spatialparams/implicitspatialparams1p.hh> -#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> -#include <dumux/material/fluidmatrixinteractions/1p/thermalconductivityaverage.hh> -#include <dumux/material/fluidstates/compositionalfluidstate.hh> - -namespace Dumux -{ -// \{ -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Property values -////////////////////////////////////////////////////////////////// - - -SET_INT_PROP(OnePTwoC, NumEq, 2); //!< set the number of equations to 2 -SET_INT_PROP(OnePTwoC, NumPhases, 1); //!< The number of phases in the 1p2c model is 1 -SET_INT_PROP(OnePTwoC, NumComponents, 2); //!< The number of components in the 1p2c model is 2 -SET_SCALAR_PROP(OnePTwoC, Scaling, 1); //!< Scaling of the model is set to 1 by default -SET_BOOL_PROP(OnePTwoC, UseMoles, true); //!< Define that mole fractions are used in the balance equations - -//! Use the 1p2c local residual function for the 1p2c model -SET_TYPE_PROP(OnePTwoC, LocalResidual, OnePTwoCLocalResidual<TypeTag>); - -//! define the model -SET_TYPE_PROP(OnePTwoC, Model, OnePTwoCModel<TypeTag>); - -//! define the VolumeVariables -SET_TYPE_PROP(OnePTwoC, VolumeVariables, OnePTwoCVolumeVariables<TypeTag>); - -//! define the FluxVariables -SET_TYPE_PROP(OnePTwoC, FluxVariables, OnePTwoCFluxVariables<TypeTag>); - -/*! - * \brief The fluid state which is used by the volume variables to - * store the thermodynamic state. This should be chosen - * appropriately for the model ((non-)isothermal, equilibrium, ...). - * This can be done in the problem. - */ -SET_PROP(OnePTwoC, 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 weight to 1.0, i.e. fully upwind -SET_SCALAR_PROP(OnePTwoC, ImplicitMassUpwindWeight, 1.0); - -//! weight for the upwind mobility in the velocity calculation -SET_SCALAR_PROP(OnePTwoC, ImplicitMobilityUpwindWeight, 1.0); - -//! Set the indices used by the 1p2c model -SET_TYPE_PROP(OnePTwoC, Indices, OnePTwoCIndices<TypeTag>); -//! The spatial parameters to be employed. -//! Use ImplicitSpatialParamsOneP by default. -SET_TYPE_PROP(OnePTwoC, SpatialParams, ImplicitSpatialParamsOneP<TypeTag>); - -//! The model after Millington (1961) is used for the effective diffusivity -SET_PROP(OnePTwoC, EffectiveDiffusivityModel) -{ private : - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - public: - typedef DiffusivityMillingtonQuirk<Scalar> type; -}; - -//! Set the phaseIndex per default to zero (important for two-phase fluidsystems). -SET_INT_PROP(OnePTwoC, PhaseIdx, 0); - -// disable velocity output by default -SET_BOOL_PROP(OnePTwoC, VtkAddVelocity, false); - -// enable gravity by default -SET_BOOL_PROP(OnePTwoC, ProblemEnableGravity, true); - -//! default value for the forchheimer coefficient -// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. -// Actually the Forchheimer coefficient is also a function of the dimensions of the -// porous medium. Taking it as a constant is only a first approximation -// (Nield, Bejan, Convection in porous media, 2006, p. 10) -SET_SCALAR_PROP(OnePTwoC, SpatialParamsForchCoeff, 0.55); - -//! average is used as default model to compute the effective thermal heat conductivity -SET_PROP(OnePTwoCNI, ThermalConductivityModel) -{ private : - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - public: - typedef ThermalConductivityAverage<Scalar> type; -}; - -////////////////////////////////////////////////////////////////// -// Property values for isothermal model required for the general non-isothermal model -////////////////////////////////////////////////////////////////// - -// set isothermal Model -SET_TYPE_PROP(OnePTwoCNI, IsothermalModel, OnePTwoCModel<TypeTag>); - -// set isothermal FluxVariables -SET_TYPE_PROP(OnePTwoCNI, IsothermalFluxVariables, OnePTwoCFluxVariables<TypeTag>); - -//set isothermal VolumeVariables -SET_TYPE_PROP(OnePTwoCNI, IsothermalVolumeVariables, OnePTwoCVolumeVariables<TypeTag>); - -//set isothermal LocalResidual -SET_TYPE_PROP(OnePTwoCNI, IsothermalLocalResidual, OnePTwoCLocalResidual<TypeTag>); - -//set isothermal Indices -SET_TYPE_PROP(OnePTwoCNI, IsothermalIndices, OnePTwoCIndices<TypeTag>); - -//set isothermal NumEq -SET_INT_PROP(OnePTwoCNI, IsothermalNumEq, 2); - - -} -// \} -} +#include <dumux/porousmediumflow/1p2c/implicit/propertydefaults.hh> #endif - diff --git a/dumux/implicit/1p2c/1p2cvolumevariables.hh b/dumux/implicit/1p2c/1p2cvolumevariables.hh index f056c80b52..df0103b0d2 100644 --- a/dumux/implicit/1p2c/1p2cvolumevariables.hh +++ b/dumux/implicit/1p2c/1p2cvolumevariables.hh @@ -1,287 +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 box - * model defined on a vertex. - */ -#ifndef DUMUX_1P2C_VOLUME_VARIABLES_HH -#define DUMUX_1P2C_VOLUME_VARIABLES_HH +#ifndef DUMUX_1P2C_VOLUME_VARIABLES_HH_OLD +#define DUMUX_1P2C_VOLUME_VARIABLES_HH_OLD -#include <dumux/implicit/volumevariables.hh> +#warning this header is deprecated, use dumux/porousmediumflow/1p2c/implicit/volumevariables.hh instead -#include "1p2cproperties.hh" - -namespace Dumux -{ - -/*! - * \ingroup OnePTwoCModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are constant within a - * finite volume in the single-phase, two-component model. - */ -template <class TypeTag> -class OnePTwoCVolumeVariables : 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, FluidSystem) FluidSystem; - static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - phaseIdx = Indices::phaseIdx, - phaseCompIdx = Indices::phaseCompIdx, - transportCompIdx = Indices::transportCompIdx - }; - //indices of primary variables - enum{ - pressureIdx = Indices::pressureIdx, - massOrMoleFracIdx = Indices::massOrMoleFracIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - enum { dim = GridView::dimension }; - enum { dimWorld = GridView::dimensionworld }; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar,dim> DimVector; - typedef Dune::FieldVector<Scalar,dimWorld> GlobalPosition; - -public: - - typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; - - /*! - * \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); - - //calculate all secondary variables from the primary variables and store results in fluidstate - completeFluidState(priVars, problem, element, fvGeometry, scvIdx, fluidState_); - - porosity_ = problem.spatialParams().porosity(element, fvGeometry, scvIdx); - - dispersivity_ = problem.spatialParams().dispersivity(element, fvGeometry, scvIdx); - - // Second instance of a parameter cache. - // Could be avoided if diffusion coefficients also - // became part of the fluid state. - typename FluidSystem::ParameterCache paramCache; - paramCache.updatePhase(fluidState_, phaseIdx); - - diffCoeff_ = FluidSystem::binaryDiffusionCoefficient(fluidState_, - paramCache, - phaseIdx, - phaseCompIdx, - transportCompIdx); - - Valgrind::CheckDefined(porosity_); - Valgrind::CheckDefined(dispersivity_); - Valgrind::CheckDefined(diffCoeff_); - - // energy related quantities not contained in the fluid state - asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol); - } - - /*! - * \copydoc ImplicitModel::completeFluidState - */ - static void completeFluidState(const PrimaryVariables& priVars, - const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - const int scvIdx, - FluidState& fluidState) - { - Scalar t = Implementation::temperature_(priVars, problem, element, - fvGeometry, scvIdx); - fluidState.setTemperature(t); - fluidState.setSaturation(phaseIdx, 1.); - - fluidState.setPressure(phaseIdx, priVars[pressureIdx]); - - if(useMoles) - { - fluidState.setMoleFraction(phaseIdx, phaseCompIdx, 1 - priVars[massOrMoleFracIdx]); - fluidState.setMoleFraction(phaseIdx, transportCompIdx, priVars[massOrMoleFracIdx]); - } - else - { - // setMassFraction() has only to be called 1-numComponents times - fluidState.setMassFraction(phaseIdx, transportCompIdx, priVars[massOrMoleFracIdx]); - } - - typename FluidSystem::ParameterCache paramCache; - paramCache.updatePhase(fluidState, phaseIdx); - - Scalar value; - value = FluidSystem::density(fluidState, paramCache, phaseIdx); - fluidState.setDensity(phaseIdx, value); - value = FluidSystem::viscosity(fluidState, paramCache, phaseIdx); - fluidState.setViscosity(phaseIdx, value); - - // compute and set the enthalpy - Scalar h = Implementation::enthalpy_(fluidState, paramCache, phaseIdx); - fluidState.setEnthalpy(phaseIdx, h); - } - - /*! - * \brief Return the fluid configuration at the given primary - * variables - */ - const FluidState &fluidState() const - { return fluidState_; } - - /*! - * \brief Return density \f$\mathrm{[kg/m^3]}\f$ the of the fluid phase. - */ - Scalar density() const - { return fluidState_.density(phaseIdx); } - - /*! - * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ the of the fluid phase. - */ - Scalar molarDensity() const - { return fluidState_.molarDensity(phaseIdx);} - - /*! - * \brief Return mole fraction \f$\mathrm{[mol/mol]}\f$ of a component in the phase. - * - * \param compIdx The index of the component - */ - Scalar moleFraction(int compIdx) const - { return fluidState_.moleFraction(phaseIdx, (compIdx==0)?phaseCompIdx:transportCompIdx); } - - /*! - * \brief Return mass fraction \f$\mathrm{[kg/kg]}\f$ of a component in the phase. - * - * \param compIdx The index of the component - */ - Scalar massFraction(int compIdx) const - { return fluidState_.massFraction(phaseIdx, (compIdx==0)?phaseCompIdx:transportCompIdx); } - - /*! - * \brief Return concentration \f$\mathrm{[mol/m^3]}\f$ of a component in the phase. - * - * \param compIdx The index of the component - */ - Scalar molarity(int compIdx) const - { return fluidState_.molarity(phaseIdx, (compIdx==0)?phaseCompIdx:transportCompIdx); } - - /*! - * \brief Return the effective pressure \f$\mathrm{[Pa]}\f$ of a given phase within - * the control volume. - */ - Scalar pressure() const - { return fluidState_.pressure(phaseIdx); } - - /*! - * \brief Return the binary diffusion coefficient \f$\mathrm{[m^2/s]}\f$ in the fluid. - */ - Scalar diffCoeff() const - { return diffCoeff_; } - - /*! - * \brief Returns the dispersivity of the fluid's streamlines. - */ - const GlobalPosition &dispersivity() const - { return dispersivity_; } - - /*! - * \brief Return temperature \f$\mathrm{[K]}\f$ inside the sub-control volume. - * - * Note that we assume thermodynamic equilibrium, i.e. the - * temperature of the rock matrix and of all fluid phases are - * identical. - */ - Scalar temperature() const - { return fluidState_.temperature(phaseIdx); } - - /*! - * \brief Return the dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of a given phase - * within the control volume. - */ - Scalar viscosity() const - { return fluidState_.viscosity(phaseIdx); } - - /*! - * \brief Return the average porosity \f$\mathrm{[-]}\f$ within the control volume. - */ - Scalar porosity() const - { return porosity_; } - -protected: - static Scalar temperature_(const PrimaryVariables &priVars, - const Problem& problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx) - { - return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); - } - - template<class ParameterCache> - static Scalar enthalpy_(const FluidState& fluidState, - const ParameterCache& paramCache, - const int phaseIdx) - { - return 0; - } - - /*! - * \brief Called by update() to compute the energy related quantities. - */ - void updateEnergy_(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx, - const bool isOldSol) - { } - - Scalar porosity_; //!< Effective porosity within the control volume - GlobalPosition dispersivity_; - Scalar diffCoeff_; - FluidState fluidState_; - -private: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } -}; - -}// end namespace +#include <dumux/porousmediumflow/1p2c/implicit/volumevariables.hh> #endif diff --git a/dumux/implicit/2p2c/2p2cfluxvariables.hh b/dumux/implicit/2p2c/2p2cfluxvariables.hh index 8f0487eb25..7adf5ca5a5 100644 --- a/dumux/implicit/2p2c/2p2cfluxvariables.hh +++ b/dumux/implicit/2p2c/2p2cfluxvariables.hh @@ -1,255 +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 Contains the data which is required to calculate - * all fluxes of components over a face of a finite volume for - * the two-phase two-component model fully implicit model. - */ -#ifndef DUMUX_2P2C_FLUX_VARIABLES_HH -#define DUMUX_2P2C_FLUX_VARIABLES_HH +#ifndef DUMUX_2P2C_FLUX_VARIABLES_HH_OLD +#define DUMUX_2P2C_FLUX_VARIABLES_HH_OLD -#include <dumux/common/math.hh> -#include <dumux/common/spline.hh> +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/fluxvariables.hh instead -#include "2p2cproperties.hh" - -namespace Dumux -{ - -/*! - * \ingroup TwoPTwoCModel - * \ingroup ImplicitFluxVariables - * \brief Contains the data which is required to calculate - * all fluxes of components over a face of a finite volume for - * the two-phase two-component model fully implicit model. - * - * This means pressure and concentration gradients, phase densities at - * the integration point, etc. - */ -template <class TypeTag> -class TwoPTwoCFluxVariables : public GET_PROP_TYPE(TypeTag, BaseFluxVariables) -{ - typedef typename GET_PROP_TYPE(TypeTag, BaseFluxVariables) BaseFluxVariables; - 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; - enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - wCompIdx = Indices::wCompIdx, - nCompIdx = Indices::nCompIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - enum { dim = GridView::dimension }; - enum { dimWorld = GridView::dimensionworld} ; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - - 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 sub-control-volume face - * \param elemVolVars The volume variables of the current element - * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face - */ - TwoPTwoCFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : BaseFluxVariables(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) - { - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - density_[phaseIdx] = Scalar(0); - molarDensity_[phaseIdx] = Scalar(0); - moleFractionGrad_[phaseIdx] = Scalar(0); - } - - calculateValues_(problem, element, elemVolVars); - } - - protected: - void calculateValues_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - // calculate densities at the integration points of the face - GlobalPosition tmp(0.0); - for (unsigned int idx = 0; - idx < this->face().numFap; - idx++) // loop over adjacent vertices - { - // index for the element volume variables - int volVarsIdx = this->face().fapIndices[idx]; - - for (int phaseIdx = 0; phaseIdx < numPhases; phaseIdx++) - { - density_[phaseIdx] += elemVolVars[volVarsIdx].density(phaseIdx)* - this->face().shapeValue[idx]; - molarDensity_[phaseIdx] += elemVolVars[volVarsIdx].molarDensity(phaseIdx)* - this->face().shapeValue[idx]; - } - } - - calculateGradients_(problem, element, elemVolVars); - calculatePorousDiffCoeff_(problem, element, elemVolVars); - } - - void calculateGradients_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - // calculate gradients - GlobalPosition tmp(0.0); - for (unsigned int idx = 0; - idx < this->face().numFap; - idx++) // loop over adjacent vertices - { - // FE gradient at vertex idx - const GlobalPosition &feGrad = this->face().grad[idx]; - - // index for the element volume variables - int volVarsIdx = this->face().fapIndices[idx]; - - // the mole fraction gradient of the wetting phase - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, nCompIdx); - moleFractionGrad_[wPhaseIdx] += tmp; - - // the mole fraction gradient of the non-wetting phase - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, wCompIdx); - moleFractionGrad_[nPhaseIdx] += tmp; - } - } - - Scalar rhoFactor_(int phaseIdx, int scvIdx, const ElementVolumeVariables &vDat) - { - static const Scalar eps = 1e-2; - const Scalar sat = vDat[scvIdx].density(phaseIdx); - if (sat > eps) - return 0.5; - if (sat <= 0) - return 0; - - static const Dumux::Spline<Scalar> sp(0, eps, // x0, x1 - 0, 0.5, // y0, y1 - 0, 0); // m0, m1 - return sp.eval(sat); - } - - void calculatePorousDiffCoeff_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - const VolumeVariables &volVarsI = elemVolVars[this->face().i]; - const VolumeVariables &volVarsJ = elemVolVars[this->face().j]; - - // the effective diffusion coefficients at vertex i and j - Scalar diffCoeffI; - Scalar diffCoeffJ; - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - // make sure to only calculate diffusion coefficients - // for phases which exist in both finite volumes - if (volVarsI.saturation(phaseIdx) <= 0 || volVarsJ.saturation(phaseIdx) <= 0) - { - porousDiffCoeff_[phaseIdx] = 0.0; - continue; - } - - diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), - volVarsI.saturation(phaseIdx), - volVarsI.diffCoeff(phaseIdx)); - - diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), - volVarsJ.saturation(phaseIdx), - volVarsJ.diffCoeff(phaseIdx)); - - // -> harmonic mean - porousDiffCoeff_[phaseIdx] = harmonicMean(diffCoeffI, diffCoeffJ); - } - } - - public: - /*! - * \brief Returns the effective diffusion coefficient \f$\mathrm{[m^2/s]}\f$ - * for each fluid phase in the porous medium. - * - * \param phaseIdx The phase index - */ - Scalar porousDiffCoeff(int phaseIdx) const - { return porousDiffCoeff_[phaseIdx]; }; - - /*! - * \brief Returns the density \f$\mathrm{[kg/m^3]}\f$ of a phase. - * - * \param phaseIdx The phase index - */ - Scalar density(int phaseIdx) const - { return density_[phaseIdx]; } - - /*! - * \brief Returns the molar density \f$\mathrm{[mol/m^3]}\f$ of a phase. - * - * \param phaseIdx The phase index - */ - Scalar molarDensity(int phaseIdx) const - { return molarDensity_[phaseIdx]; } - - /*! - * \brief Returns the mole fraction gradient \f$\mathrm{[1/m]}\f$ - * of the dissolved component in a phase. - * - * \param phaseIdx The phase index - */ - const GlobalPosition &moleFractionGrad(int phaseIdx) const - { return moleFractionGrad_[phaseIdx]; }; - - protected: - // mole fraction gradients - GlobalPosition moleFractionGrad_[numPhases]; - - // density of each face at the integration point - Scalar density_[numPhases], molarDensity_[numPhases]; - - // the diffusion coefficient for the porous medium - Scalar porousDiffCoeff_[numPhases]; -}; - -} // end namespace +#include <dumux/porousmediumflow/2p2c/implicit/fluxvariables.hh> #endif diff --git a/dumux/implicit/2p2c/2p2cindices.hh b/dumux/implicit/2p2c/2p2cindices.hh index c38f751efa..78016b2c91 100644 --- a/dumux/implicit/2p2c/2p2cindices.hh +++ b/dumux/implicit/2p2c/2p2cindices.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/>. * - *****************************************************************************/ +#ifndef DUMUX_2P2C_INDICES_HH_OLD +#define DUMUX_2P2C_INDICES_HH_OLD -/*! - * \file - * \brief Defines the indices required for the two-phase two-component - * fully implicit model. - */ -#ifndef DUMUX_2P2C_INDICES_HH -#define DUMUX_2P2C_INDICES_HH +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/indices.hh instead -#include "2p2cproperties.hh" - -namespace Dumux -{ -// \{ - -/*! - * \ingroup TwoPTwoCModel - * \ingroup ImplicitIndices - * \brief Enumerates the formulations which the two-phase two-component model accepts. - */ -struct TwoPTwoCFormulation -{ - static const int pwsn = 0; //!< pw and sn as primary variables - static const int pnsw = 1; //!< pn and sw as primary variables -}; - -/*! - * \ingroup TwoPTwoCModel - * \ingroup ImplicitIndices - * \brief The indices for the isothermal two-phase two-component model. - * - * \tparam formulation The formulation, either pwsn or pnsw. - * \tparam PVOffset The first index in a primary variable vector. - */ -template <class TypeTag, - int formulation = TwoPTwoCFormulation::pwsn, - int PVOffset = 0> -class TwoPTwoCIndices -{ - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - -public: - // Phase indices - static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< Index of the wetting phase - static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< Index of the non-wetting phase - - // Component indices - static const int wCompIdx = FluidSystem::wCompIdx; //!< Index of the primary component of the wetting phase - static const int nCompIdx = FluidSystem::nCompIdx; //!< Index of the primary component of the non-wetting phase - - // present phases (-> 'pseudo' primary variable) - static const int wPhaseOnly = 1; //!< Only the wetting phase is present - static const int nPhaseOnly = 0; //!< Only the non-wetting phase is present - static const int bothPhases = 2; //!< Both phases are present - - // Primary variable indices - //! Index for wetting/non-wetting phase pressure (depending on the formulation) in a solution vector - static const int pressureIdx = PVOffset + 0; - //! Index of either the saturation or the mass fraction of the non-wetting/wetting phase - static const int switchIdx = PVOffset + 1; - - //! Index for wetting phase pressure in a solution vector - static const int pwIdx = pressureIdx; - //! Index of either the saturation of the non-wetting phase or the mass fraction secondary component in the only phase - static const int snOrXIdx = switchIdx; - - // equation indices - //! Index of the mass conservation equation for the first component - static const int conti0EqIdx = PVOffset; - //! Index of the mass conservation equation for the primary component of the wetting phase - static const int contiWEqIdx = conti0EqIdx + wCompIdx; - //! Index of the mass conservation equation for the primary component of the non-wetting phase - static const int contiNEqIdx = conti0EqIdx + nCompIdx; -}; - -/*! - * \ingroup TwoPTwoCModel - * \ingroup ImplicitIndices - * \brief The indices for the isothermal two-phase two-component model in the pn-sw - * formulation. - * - * \tparam PVOffset The first index in a primary variable vector. - */ -template <class TypeTag, int PVOffset> -class TwoPTwoCIndices<TypeTag, TwoPTwoCFormulation::pnsw, PVOffset> -{ - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - -public: - // Phase indices - static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< Index of the wetting phase - static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< Index of the non-wetting phase - - // Component indices - static const int wCompIdx = FluidSystem::wCompIdx; //!< Index of the primary component of the wetting phase - static const int nCompIdx = FluidSystem::nCompIdx; //!< Index of the primary component of the non-wetting phase - - // present phases (-> 'pseudo' primary variable) - static const int wPhaseOnly = 1; //!< Only the wetting phase is present - static const int nPhaseOnly = 2; //!< Only the non-wetting phase is present - static const int bothPhases = 3; //!< Both phases are present - - // Primary variable indices - //! Index for wetting/non-wetting phase pressure (depending on the formulation) in a solution vector - static const int pressureIdx = PVOffset + 0; - //! Index of either the saturation or the mass fraction of the non-wetting/wetting phase - static const int switchIdx = PVOffset + 1; - - //! Index for non-wetting phase pressure in a solution vector - static const int pnIdx = pressureIdx; - //! Index of either the saturation of the liquid phase or the mass fraction of the secondary component in the only phase - static const int swOrXIdx = switchIdx; - - // Equation indices - //! Index of the mass conservation equation for the first component - static const int conti0EqIdx = PVOffset; - //! Index of the mass conservation equation for the primary component of the wetting phase - static const int contiWEqIdx = conti0EqIdx + wCompIdx; - //! Index of the mass conservation equation for the primary component of the non-wetting phase - static const int contiNEqIdx = conti0EqIdx + nCompIdx; -}; - -// \} - -} +#include <dumux/porousmediumflow/2p2c/implicit/indices.hh> #endif diff --git a/dumux/implicit/2p2c/2p2clocalresidual.hh b/dumux/implicit/2p2c/2p2clocalresidual.hh index 3a5dcfcfd2..42750ec567 100644 --- a/dumux/implicit/2p2c/2p2clocalresidual.hh +++ b/dumux/implicit/2p2c/2p2clocalresidual.hh @@ -1,507 +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 Jacobian matrix for problems - * using the two-phase two-component fully implicit model. - */ +#ifndef DUMUX_2P2C_LOCAL_RESIDUAL_BASE_HH_OLD +#define DUMUX_2P2C_LOCAL_RESIDUAL_BASE_HH_OLD -#ifndef DUMUX_2P2C_LOCAL_RESIDUAL_BASE_HH -#define DUMUX_2P2C_LOCAL_RESIDUAL_BASE_HH +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/localresidual.hh instead -#include "2p2cproperties.hh" - -namespace Dumux -{ -/*! - * \ingroup TwoPTwoCModel - * \ingroup ImplicitLocalResidual - * \brief Element-wise calculation of the Jacobian matrix for problems - * using the two-phase two-component fully implicit model. - * - * This class is used to fill the gaps in ImplicitLocalResidual for the - * two-phase two-component flow. - */ -template<class TypeTag> -class TwoPTwoCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) -{ - protected: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - enum - { - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents) - }; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum - { - contiWEqIdx = Indices::contiWEqIdx, - contiNEqIdx = Indices::contiNEqIdx, - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - wCompIdx = Indices::wCompIdx, - nCompIdx = Indices::nCompIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - - static constexpr unsigned int replaceCompEqIdx = - GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx); - - //! Property that defines whether mole or mass fractions are used - static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); - - public: - /*! - * \brief Constructor - * - * Sets the mass upwind weight. - */ - TwoPTwoCLocalResidual() - { - // 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 storage term of the current solution in a - * single phase. - * - * \param element The element - * \param phaseIdx The index of the fluid phase - */ - void evalPhaseStorage(const Element &element, const int phaseIdx) - { - FVElementGeometry fvGeometry; - fvGeometry.update(this->gridView_(), element); - ElementBoundaryTypes bcTypes; - bcTypes.update(this->problem_(), element, fvGeometry); - ElementVolumeVariables elemVolVars; - elemVolVars.update(this->problem_(), element, fvGeometry, false); - - this->storageTerm_.resize(fvGeometry.numScv); - this->storageTerm_ = 0; - - this->elemPtr_ = &element; - this->fvElemGeomPtr_ = &fvGeometry; - this->bcTypesPtr_ = &bcTypes; - this->prevVolVarsPtr_ = 0; - this->curVolVarsPtr_ = &elemVolVars; - evalPhaseStorage_(phaseIdx); - } - - /*! - * \brief Evaluate the amount of all conservation quantities - * (e.g. phase mass) within a sub-control volume. - * - * \param storage The mass of the component within the sub-control volume - * \param scvIdx The sub-control-volume index - * \param usePrevSol Based on usePrevSol solution of current or previous time step is used - * - * The result should be averaged over the volume (e.g. phase mass - * inside a sub-control volume divided by the volume) - */ - void computeStorage(PrimaryVariables &storage, const 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]; - - // compute storage term of all components within all phases - storage = 0; - if(useMoles) // mole-fraction formulation - { - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) - { - unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; - storage[eqIdx] += volVars.molarDensity(phaseIdx) - * volVars.saturation(phaseIdx) - * volVars.moleFraction(phaseIdx, compIdx); - } - // this is only processed if one component mass balance equation - // is replaced by the total mass balance equation - if (replaceCompEqIdx < numComponents) - storage[replaceCompEqIdx] += - volVars.molarDensity(phaseIdx) - * volVars.saturation(phaseIdx); - } - storage *= volVars.porosity(); - } - else // mass-fraction formulation - { - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) - { - unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; - storage[eqIdx] += volVars.density(phaseIdx) - * volVars.saturation(phaseIdx) - * volVars.massFraction(phaseIdx, compIdx); - } - // this is only processed if one component mass balance equation - // is replaced by the total mass balance equation - if (replaceCompEqIdx < numComponents) - storage[replaceCompEqIdx] += - volVars.density(phaseIdx) - * volVars.saturation(phaseIdx); - } - storage *= volVars.porosity(); - } - } - - /*! - * \brief Evaluates the total flux of all conservation quantities - * over a face of a sub-control volume. - * - * \param flux The flux over the sub-control-volume face for each component - * \param fIdx The index of the sub-control-volume face - * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face - */ - void computeFlux(PrimaryVariables &flux, const int fIdx, bool onBoundary=false) const - { - FluxVariables fluxVars(this->problem_(), - this->element_(), - this->fvGeometry_(), - fIdx, - this->curVolVars_(), - onBoundary); - - flux = 0; - asImp_()->computeAdvectiveFlux(flux, fluxVars); - Valgrind::CheckDefined(flux); - asImp_()->computeDiffusiveFlux(flux, fluxVars); - Valgrind::CheckDefined(flux); - } - - /*! - * \brief Evaluates the advective mass flux of all components over - * a face of a sub-control volume. - * - * \param flux The flux over the sub-control-volume face for each component - * \param fluxVars The flux variables at the current sub-control-volume face - */ - void computeAdvectiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const - { - //////// - // advective fluxes of all components in all phases - //////// - - if(useMoles) // mole-fraction formulation - { - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - // 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)); - - for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) - { - unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; - // add advective flux of current component in current - // phase - if (massUpwindWeight_ > 0.0) - // upstream vertex - flux[eqIdx] += - fluxVars.volumeFlux(phaseIdx) - * massUpwindWeight_ - * up.molarDensity(phaseIdx) - * up.moleFraction(phaseIdx, compIdx); - if (massUpwindWeight_ < 1.0) - // downstream vertex - flux[eqIdx] += - fluxVars.volumeFlux(phaseIdx) - * (1 - massUpwindWeight_) - * dn.molarDensity(phaseIdx) - * dn.moleFraction(phaseIdx, compIdx); - - Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); - Valgrind::CheckDefined(up.molarDensity(phaseIdx)); - Valgrind::CheckDefined(up.moleFraction(phaseIdx, compIdx)); - Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); - Valgrind::CheckDefined(dn.moleFraction(phaseIdx, compIdx)); - } - // flux of the total mass balance; - // this is only processed if one component mass balance equation - // is replaced by a total mass balance equation - if (replaceCompEqIdx < numComponents) - { - // upstream vertex - if (massUpwindWeight_ > 0.0) - flux[replaceCompEqIdx] += - fluxVars.volumeFlux(phaseIdx) - * massUpwindWeight_ - * up.molarDensity(phaseIdx); - // downstream vertex - if (massUpwindWeight_ < 1.0) - flux[replaceCompEqIdx] += - fluxVars.volumeFlux(phaseIdx) - * (1 - massUpwindWeight_) - * dn.molarDensity(phaseIdx); - Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); - Valgrind::CheckDefined(up.molarDensity(phaseIdx)); - Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); - - } - - } - } - else // mass-fraction formulation - { - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - // data attached to upstream and downstream vertices - // of the current phase - const VolumeVariables &up = - this->curVolVars_(fluxVars.upstreamIdx(phaseIdx)); - const VolumeVariables &dn = - this->curVolVars_(fluxVars.downstreamIdx(phaseIdx)); - - for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) - { - unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; - // add advective flux of current component in current - // phase - if (massUpwindWeight_ > 0.0) - // upstream vertex - flux[eqIdx] += - fluxVars.volumeFlux(phaseIdx) - * massUpwindWeight_ - * up.density(phaseIdx) - * up.massFraction(phaseIdx, compIdx); - if (massUpwindWeight_ < 1.0) - // downstream vertex - flux[eqIdx] += - fluxVars.volumeFlux(phaseIdx) - * (1 - massUpwindWeight_) - * dn.density(phaseIdx) - * dn.massFraction(phaseIdx, compIdx); - - Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); - Valgrind::CheckDefined(up.density(phaseIdx)); - Valgrind::CheckDefined(up.massFraction(phaseIdx, compIdx)); - Valgrind::CheckDefined(dn.density(phaseIdx)); - Valgrind::CheckDefined(dn.massFraction(phaseIdx, compIdx)); - } - // flux of the total mass balance; - // this is only processed if one component mass balance equation - // is replaced by a total mass balance equation - if (replaceCompEqIdx < numComponents) - { - // upstream vertex - if (massUpwindWeight_ > 0.0) - flux[replaceCompEqIdx] += - fluxVars.volumeFlux(phaseIdx) - * massUpwindWeight_ - * up.density(phaseIdx); - // downstream vertex - if (massUpwindWeight_ < 1.0) - flux[replaceCompEqIdx] += - fluxVars.volumeFlux(phaseIdx) - * (1 - massUpwindWeight_) - * dn.density(phaseIdx); - Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); - Valgrind::CheckDefined(up.density(phaseIdx)); - Valgrind::CheckDefined(dn.density(phaseIdx)); - - } - - } - } - } - - /*! - * \brief Evaluates the diffusive mass flux of all components over - * a face of a sub-control volume. - * - * \param flux The 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 - - { - if(useMoles) // mole-fraction formulation - { - // add diffusive flux of gas component in liquid phase - Scalar tmp = - (fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal); - tmp *= - fluxVars.porousDiffCoeff(wPhaseIdx) * - fluxVars.molarDensity(wPhaseIdx); - // add the diffusive fluxes only to the component mass balance - if (replaceCompEqIdx != contiNEqIdx) - flux[contiNEqIdx] += tmp; - if (replaceCompEqIdx != contiWEqIdx) - flux[contiWEqIdx] -= tmp; - - // add diffusive flux of liquid component in non-wetting phase - tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal); - tmp *= - fluxVars.porousDiffCoeff(nPhaseIdx) * - fluxVars.molarDensity(nPhaseIdx); - // add the diffusive fluxes only to the component mass balance - if (replaceCompEqIdx != contiWEqIdx) - flux[contiWEqIdx] += tmp; - if (replaceCompEqIdx != contiNEqIdx) - flux[contiNEqIdx] -= tmp; - } - else // mass-fraction formulation - { - // add diffusive flux of gas component in liquid phase - Scalar tmp = - (fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal); - tmp *= - fluxVars.porousDiffCoeff(wPhaseIdx) * - fluxVars.molarDensity(wPhaseIdx); - // add the diffusive fluxes only to the component mass balance - if (replaceCompEqIdx != contiNEqIdx) - flux[contiNEqIdx] += tmp * FluidSystem::molarMass(nCompIdx); - if (replaceCompEqIdx != contiWEqIdx) - flux[contiWEqIdx] -= tmp * FluidSystem::molarMass(wCompIdx); - - // add diffusive flux of liquid component in non-wetting phase - tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal); - tmp *= - fluxVars.porousDiffCoeff(nPhaseIdx) * - fluxVars.molarDensity(nPhaseIdx); - // add the diffusive fluxes only to the component mass balance - if (replaceCompEqIdx != contiWEqIdx) - flux[contiWEqIdx] += tmp * FluidSystem::molarMass(wCompIdx); - if (replaceCompEqIdx != contiNEqIdx) - flux[contiNEqIdx] -= tmp * FluidSystem::molarMass(nCompIdx); - } - } - - protected: - void evalPhaseStorage_(const int phaseIdx) - { - if(useMoles) // mole-fraction formulation - { - // evaluate the storage terms of a single phase - for (int i=0; i < this->fvGeometry_().numScv; i++) { - PrimaryVariables &storage = this->storageTerm_[i]; - const ElementVolumeVariables &elemVolVars = this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[i]; - - // compute storage term of all components within all phases - storage = 0; - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; - storage[eqIdx] += volVars.molarDensity(phaseIdx) - * volVars.saturation(phaseIdx) - * volVars.moleFraction(phaseIdx, compIdx); - } - - storage *= volVars.porosity(); - storage *= this->fvGeometry_().subContVol[i].volume; - } - } - else // mass-fraction formulation - { - // evaluate the storage terms of a single phase - for (int i=0; i < this->fvGeometry_().numScv; i++) { - PrimaryVariables &storage = this->storageTerm_[i]; - const ElementVolumeVariables &elemVolVars = this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[i]; - - // compute storage term of all components within all phases - storage = 0; - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; - storage[eqIdx] += volVars.density(phaseIdx) - * volVars.saturation(phaseIdx) - * volVars.massFraction(phaseIdx, compIdx); - } - - storage *= volVars.porosity(); - storage *= this->fvGeometry_().subContVol[i].volume; - } - } - } - - /*! - * \brief Returns the equation index of the first mass-balance equation - * of the component (used for loops) - * - * Returns the equation index of the first mass-balance equation - * of the component (used for loops) if one component mass balance - * is replaced by the total mass balance, this is the index - * of the remaining component mass-balance equation. - */ - unsigned int contiCompIdx1_() const { - switch (replaceCompEqIdx) - { - case contiWEqIdx: return contiNEqIdx; - case contiNEqIdx: return contiWEqIdx; - default: return 0; - } - } - - /*! - * \brief Returns the equation index of the second mass balance - * of the component (used for loops) - * - * Returns the equation index of the second mass balance - * of the component (used for loops) - * if one component mass balance is replaced by the total mass balance - * (replaceCompEqIdx < 2), this index is the same as contiCompIdx1(). - */ - unsigned int contiCompIdx2_() const { - switch (replaceCompEqIdx) - { - case contiWEqIdx: return contiNEqIdx; - case contiNEqIdx: return contiWEqIdx; - default: return numComponents-1; - } - } - - Implementation *asImp_() - { return static_cast<Implementation *> (this); } - const Implementation *asImp_() const - { return static_cast<const Implementation *> (this); } - - private: - Scalar massUpwindWeight_; -}; - -} // end namespace +#include <dumux/porousmediumflow/2p2c/implicit/localresidual.hh> #endif diff --git a/dumux/implicit/2p2c/2p2cmodel.hh b/dumux/implicit/2p2c/2p2cmodel.hh index 552fd4092c..bf4ab0d68c 100644 --- a/dumux/implicit/2p2c/2p2cmodel.hh +++ b/dumux/implicit/2p2c/2p2cmodel.hh @@ -1,725 +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 Adaption of the fully implicit scheme to the - * two-phase two-component fully implicit model. - */ -#ifndef DUMUX_2P2C_MODEL_HH -#define DUMUX_2P2C_MODEL_HH +#ifndef DUMUX_2P2C_MODEL_HH_OLD +#define DUMUX_2P2C_MODEL_HH_OLD -#include "2p2cproperties.hh" -#include "2p2cindices.hh" -#include <dumux/porousmediumflow/implicit/velocityoutput.hh> +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/model.hh instead -namespace Dumux -{ -/*! - * \ingroup TwoPTwoCModel - * \brief Adaption of the fully implicit scheme to the - * two-phase two-component fully implicit model. - * - * This model implements two-phase two-component flow of two compressible and - * partially miscible fluids \f$\alpha \in \{ w, n \}\f$ composed of the two components - * \f$\kappa \in \{ w, a \}\f$. The standard multiphase Darcy - * approach is used as the equation for the conservation of momentum: - * \f[ - v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mathbf{K} - \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) - * \f] - * - * By inserting this into the equations for the conservation of the - * components, one gets one transport equation for each component - * \f{eqnarray*} - && \phi \frac{\partial (\sum_\alpha \varrho_\alpha \frac{M^\kappa}{M_\alpha} x_\alpha^\kappa S_\alpha )} - {\partial t} - - \sum_\alpha \text{div} \left\{ \varrho_\alpha \frac{M^\kappa}{M_\alpha} x_\alpha^\kappa - \frac{k_{r\alpha}}{\mu_\alpha} \mathbf{K} - (\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g}) \right\} - \nonumber \\ \nonumber \\ - &-& \sum_\alpha \text{div} \left\{ D_{\alpha,\text{pm}}^\kappa \varrho_{\alpha} \frac{M^\kappa}{M_\alpha} - \textbf{grad} x^\kappa_{\alpha} \right\} - - \sum_\alpha q_\alpha^\kappa = 0 \qquad \kappa \in \{w, a\} \, , - \alpha \in \{w, g\} - \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. - * - * By using constitutive relations for the capillary pressure \f$p_c = - * p_n - p_w\f$ and relative permeability \f$k_{r\alpha}\f$ and taking - * advantage of the fact that \f$S_w + S_n = 1\f$ and \f$x^\kappa_w + x^\kappa_n = 1\f$, the number of - * unknowns can be reduced to two. - * The used primary variables are, like in the two-phase model, either \f$p_w\f$ and \f$S_n\f$ - * or \f$p_n\f$ and \f$S_w\f$. The formulation which ought to be used can be - * specified by setting the <tt>Formulation</tt> property to either - * TwoPTwoCIndices::pWsN or TwoPTwoCIndices::pNsW. By - * default, the model uses \f$p_w\f$ and \f$S_n\f$. - * Moreover, the second primary variable depends on the phase state, since a - * primary variable switch is included. The phase state is stored for all nodes - * of the system. - * The model is able to use either mole or mass fractions. The property useMoles can be set to either true or false in the - * problem file. Make sure that the according units are used in the problem setup. useMoles is set to true by default. - * Following cases can be distinguished: - * <ul> - * <li> Both phases are present: The saturation is used (either \f$S_n\f$ or \f$S_w\f$, dependent on the chosen <tt>Formulation</tt>), - * as long as \f$ 0 < S_\alpha < 1\f$</li>. - * <li> Only wetting phase is present: The mole fraction of, e.g., air in the wetting phase \f$x^a_w\f$ is used, - * as long as the maximum mole fraction is not exceeded \f$(x^a_w<x^a_{w,max})\f$</li> - * <li> Only non-wetting phase is present: The mole fraction of, e.g., water in the non-wetting phase, \f$x^w_n\f$, is used, - * as long as the maximum mole fraction is not exceeded \f$(x^w_n<x^w_{n,max})\f$</li> - * </ul> - */ - -template<class TypeTag> -class TwoPTwoCModel: public GET_PROP_TYPE(TypeTag, BaseModel) -{ - typedef typename GET_PROP_TYPE(TypeTag, BaseModel) ParentType; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - enum { - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents) - }; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - switchIdx = Indices::switchIdx, - - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - wCompIdx = Indices::wCompIdx, - nCompIdx = Indices::nCompIdx, - - wPhaseOnly = Indices::wPhaseOnly, - nPhaseOnly = Indices::nPhaseOnly, - bothPhases = Indices::bothPhases, - - pwsn = TwoPTwoCFormulation::pwsn, - pnsw = TwoPTwoCFormulation::pnsw, - formulation = GET_PROP_VALUE(TypeTag, Formulation) - }; - - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - enum { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld - }; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - -public: - /*! - * \brief Initialize the static data with the initial solution. - * - * \param problem The problem to be solved - */ - void init(Problem &problem) - { - ParentType::init(problem); - - unsigned numDofs = this->numDofs(); - - staticDat_.resize(numDofs); - - setSwitched_(false); - - // check, if velocity output can be used (works only for cubes so far) - for (const auto& element : Dune::elements(this->gridView_())) - { - if (!isBox) // i.e. cell-centered discretization - { - int eIdxGlobal = this->dofMapper().index(element); - const GlobalPosition &globalPos = element.geometry().center(); - - // initialize phase presence - staticDat_[eIdxGlobal].phasePresence - = this->problem_().initialPhasePresence(*(this->gridView_().template begin<dim>()), - eIdxGlobal, globalPos); - staticDat_[eIdxGlobal].wasSwitched = false; - - staticDat_[eIdxGlobal].oldPhasePresence - = staticDat_[eIdxGlobal].phasePresence; - } - } - - if (isBox) // i.e. vertex-centered discretization - { - for (const auto& vertex : Dune::vertices(this->gridView_())) - { - int vIdxGlobal = this->dofMapper().index(vertex); - const GlobalPosition &globalPos = vertex.geometry().corner(0); - - // initialize phase presence - staticDat_[vIdxGlobal].phasePresence - = this->problem_().initialPhasePresence(vertex, vIdxGlobal, - globalPos); - staticDat_[vIdxGlobal].wasSwitched = false; - - staticDat_[vIdxGlobal].oldPhasePresence - = staticDat_[vIdxGlobal].phasePresence; - } - } - } - - /*! - * \brief Compute the total storage of all conservation quantities in one phase - * - * \param storage Contains the storage of each component in one phase - * \param phaseIdx The phase index - */ - void globalPhaseStorage(PrimaryVariables &storage, const int phaseIdx) - { - storage = 0; - - for (const auto& element : Dune::elements(this->gridView_())) { - if(element.partitionType() == Dune::InteriorEntity) - { - - - this->localResidual().evalPhaseStorage(element, phaseIdx); - - for (unsigned int i = 0; i < this->localResidual().storageTerm().size(); ++i) - storage += this->localResidual().storageTerm()[i]; - } - } - if (this->gridView_().comm().size() > 1) - storage = this->gridView_().comm().sum(storage); - } - - /*! - * \brief Called by the update() method if applying the Newton - * method was unsuccessful. - */ - void updateFailed() - { - ParentType::updateFailed(); - - setSwitched_(false); - resetPhasePresence_(); - } - - /*! - * \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() - { - ParentType::advanceTimeLevel(); - - // update the phase state - updateOldPhasePresence_(); - setSwitched_(false); - } - - /*! - * \brief Returns true if the primary variables were switched for - * at least one vertex after the last timestep. - */ - bool switched() const - { - return switchFlag_; - } - - /*! - * \brief Returns the phase presence of the current or the old solution of a degree of freedom. - * - * \param dofIdxGlobal The global index of the degree of freedom - * \param oldSol Based on oldSol current or previous time step is used - */ - int phasePresence(int dofIdxGlobal, bool oldSol) const - { - return oldSol ? staticDat_[dofIdxGlobal].oldPhasePresence - : staticDat_[dofIdxGlobal].phasePresence; - } - - /*! - * \brief Append all quantities of interest which can be derived - * from the solution of the current time step to the VTK - * writer. - * - * \param sol The solution vector - * \param writer The writer for multi-file VTK datasets - */ - template<class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, - MultiWriter &writer) - { - typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; - typedef Dune::BlockVector<Dune::FieldVector<double, dimWorld> > VectorField; - - // get the number of degrees of freedom - unsigned numDofs = this->numDofs(); - - // create the required scalar fields - ScalarField *sN = writer.allocateManagedBuffer(numDofs); - ScalarField *sW = writer.allocateManagedBuffer(numDofs); - ScalarField *pn = writer.allocateManagedBuffer(numDofs); - ScalarField *pw = writer.allocateManagedBuffer(numDofs); - ScalarField *pc = writer.allocateManagedBuffer(numDofs); - ScalarField *rhoW = writer.allocateManagedBuffer(numDofs); - ScalarField *rhoN = writer.allocateManagedBuffer(numDofs); - ScalarField *mobW = writer.allocateManagedBuffer(numDofs); - ScalarField *mobN = writer.allocateManagedBuffer(numDofs); - ScalarField *phasePresence = writer.allocateManagedBuffer(numDofs); - ScalarField *massFrac[numPhases][numComponents]; - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - massFrac[phaseIdx][compIdx] = writer.allocateManagedBuffer(numDofs); - ScalarField *moleFrac[numPhases][numComponents]; - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - moleFrac[phaseIdx][compIdx] = writer.allocateManagedBuffer(numDofs); - ScalarField *temperature = writer.allocateManagedBuffer(numDofs); - ScalarField *poro = writer.allocateManagedBuffer(numDofs); - VectorField *velocityN = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); - VectorField *velocityW = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); - ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - // initialize velocity fields - for (unsigned int i = 0; i < numDofs; ++i) - { - (*velocityN)[i] = Scalar(0); - (*velocityW)[i] = Scalar(0); - } - } - - unsigned numElements = this->gridView_().size(0); - ScalarField *rank = writer.allocateManagedBuffer(numElements); - - for (const auto& element : Dune::elements(this->gridView_())) - { - if(element.partitionType() == Dune::InteriorEntity) - { - int eIdx = this->elementMapper().index(element); - (*rank)[eIdx] = this->gridView_().comm().rank(); - - FVElementGeometry fvGeometry; - fvGeometry.update(this->gridView_(), element); - - ElementVolumeVariables elemVolVars; - elemVolVars.update(this->problem_(), - element, - fvGeometry, - false /* oldSol? */); - - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); - - (*sN)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx); - (*sW)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx); - (*pn)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx); - (*pw)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx); - (*pc)[dofIdxGlobal] = elemVolVars[scvIdx].capillaryPressure(); - (*rhoW)[dofIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx); - (*rhoN)[dofIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx); - (*mobW)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(wPhaseIdx); - (*mobN)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(nPhaseIdx); - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - (*massFrac[phaseIdx][compIdx])[dofIdxGlobal] - = elemVolVars[scvIdx].massFraction(phaseIdx, compIdx); - - Valgrind::CheckDefined((*massFrac[phaseIdx][compIdx])[dofIdxGlobal][0]); - } - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - (*moleFrac[phaseIdx][compIdx])[dofIdxGlobal] - = elemVolVars[scvIdx].moleFraction(phaseIdx, compIdx); - - Valgrind::CheckDefined((*moleFrac[phaseIdx][compIdx])[dofIdxGlobal][0]); - } - (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity(); - (*temperature)[dofIdxGlobal] = elemVolVars[scvIdx].temperature(); - (*phasePresence)[dofIdxGlobal] - = staticDat_[dofIdxGlobal].phasePresence; - } - - // velocity output - velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); - velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); - } - - } // loop over elements - - writer.attachDofData(*sN, "Sn", isBox); - writer.attachDofData(*sW, "Sw", isBox); - writer.attachDofData(*pn, "pn", isBox); - writer.attachDofData(*pw, "pw", isBox); - writer.attachDofData(*pc, "pc", isBox); - writer.attachDofData(*rhoW, "rhoW", isBox); - writer.attachDofData(*rhoN, "rhoN", isBox); - writer.attachDofData(*mobW, "mobW", isBox); - writer.attachDofData(*mobN, "mobN", isBox); - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - std::ostringstream oss; - oss << "X_" << FluidSystem::phaseName(phaseIdx) << "^" << FluidSystem::componentName(compIdx); - writer.attachDofData(*massFrac[phaseIdx][compIdx], oss.str(), isBox); - } - } - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - std::ostringstream oss; - oss << "x_" << FluidSystem::phaseName(phaseIdx) << "^" << FluidSystem::componentName(compIdx); - writer.attachDofData(*moleFrac[phaseIdx][compIdx], oss.str(), isBox); - } - } - writer.attachDofData(*poro, "porosity", isBox); - writer.attachDofData(*temperature, "temperature", isBox); - writer.attachDofData(*phasePresence, "phase presence", isBox); - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - writer.attachDofData(*velocityW, "velocityW", isBox, dim); - writer.attachDofData(*velocityN, "velocityN", isBox, dim); - } - - writer.attachCellData(*rank, "process rank"); - } - - /*! - * \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, either a vertex or an element - */ - template<class Entity> - void serializeEntity(std::ostream &outStream, const Entity &entity) - { - // write primary variables - ParentType::serializeEntity(outStream, entity); - - int dofIdxGlobal = this->dofMapper().index(entity); - - if (!outStream.good()) - DUNE_THROW(Dune::IOError, "Could not serialize entity " << dofIdxGlobal); - - outStream << staticDat_[dofIdxGlobal].phasePresence << " "; - } - - /*! - * \brief Reads the current solution from a restart file. - * - * \param inStream The input stream of one vertex from the restart file - * \param entity The entity, either a vertex or an element - */ - template<class Entity> - void deserializeEntity(std::istream &inStream, const Entity &entity) - { - // read primary variables - ParentType::deserializeEntity(inStream, entity); - - // read phase presence - int dofIdxGlobal = this->dofMapper().index(entity); - - if (!inStream.good()) - DUNE_THROW(Dune::IOError, - "Could not deserialize entity " << dofIdxGlobal); - - inStream >> staticDat_[dofIdxGlobal].phasePresence; - staticDat_[dofIdxGlobal].oldPhasePresence - = staticDat_[dofIdxGlobal].phasePresence; - - } - - /*! - * \brief Update the static data of all vertices in the grid. - * - * \param curGlobalSol The current global solution - * \param oldGlobalSol The previous global solution - */ - void updateStaticData(SolutionVector &curGlobalSol, - const SolutionVector &oldGlobalSol) - { - bool wasSwitched = false; - int succeeded; - try { - for (unsigned i = 0; i < staticDat_.size(); ++i) - staticDat_[i].visited = false; - - FVElementGeometry fvGeometry; - static VolumeVariables volVars; - for (const auto& element : Dune::elements(this->gridView_())) - { - fvGeometry.update(this->gridView_(), element); - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); - - if (staticDat_[dofIdxGlobal].visited) - continue; - - staticDat_[dofIdxGlobal].visited = true; - volVars.update(curGlobalSol[dofIdxGlobal], - this->problem_(), - element, - fvGeometry, - scvIdx, - false); - const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (primaryVarSwitch_(curGlobalSol, - volVars, - dofIdxGlobal, - globalPos)) - { - this->jacobianAssembler().markDofRed(dofIdxGlobal); - wasSwitched = true; - } - } - } - succeeded = 1; - } - catch (Dumux::NumericalProblem &e) - { - std::cout << "\n" - << "Rank " << this->problem_().gridView().comm().rank() - << " caught an exception while updating the static data." << e.what() - << "\n"; - succeeded = 0; - } - //make sure that all processes succeeded. If not throw a NumericalProblem to decrease the time step size. - if (this->gridView_().comm().size() > 1) - succeeded = this->gridView_().comm().min(succeeded); - - if (!succeeded) { - DUNE_THROW(NumericalProblem, - "A process did not succeed in updating the static data."); - return; - } - - // make sure that if there was a variable switch in an - // other partition we will also set the switch flag - // for our partition. - if (this->gridView_().comm().size() > 1) - wasSwitched = this->gridView_().comm().max(wasSwitched); - - setSwitched_(wasSwitched); - } - - protected: - /*! - * \brief Data which is attached to each vertex and is not only - * stored locally. - */ - struct StaticVars - { - int phasePresence; - bool wasSwitched; - - int oldPhasePresence; - bool visited; - }; - - /*! - * \brief Resets the current phase presence of all vertices to the old one. - * - * This is done after an update failed. - */ - void resetPhasePresence_() - { - for (unsigned int idx = 0; idx < staticDat_.size(); ++idx) - { - staticDat_[idx].phasePresence - = staticDat_[idx].oldPhasePresence; - staticDat_[idx].wasSwitched = false; - } - } - - /*! - * \brief Sets the phase presence of all vertices state to the current one. - */ - void updateOldPhasePresence_() - { - for (unsigned int idx = 0; idx < staticDat_.size(); ++idx) - { - staticDat_[idx].oldPhasePresence - = staticDat_[idx].phasePresence; - staticDat_[idx].wasSwitched = false; - } - } - - /*! - * \brief Sets whether there was a primary variable switch after - * the last timestep. - */ - void setSwitched_(bool yesno) - { - switchFlag_ = yesno; - } - - /*! - * \brief Performs variable switch at a vertex, returns true if a - * variable switch was performed. - */ - bool primaryVarSwitch_(SolutionVector &globalSol, - const VolumeVariables &volVars, - int dofIdxGlobal, - const GlobalPosition &globalPos) - { - // evaluate primary variable switch - bool wouldSwitch = false; - int phasePresence = staticDat_[dofIdxGlobal].phasePresence; - int newPhasePresence = phasePresence; - - // check if a primary var switch is necessary - if (phasePresence == nPhaseOnly) - { - // calculate mole fraction in the hypothetic wetting phase - Scalar xww = volVars.moleFraction(wPhaseIdx, wCompIdx); - Scalar xwn = volVars.moleFraction(wPhaseIdx, nCompIdx); - - Scalar xwMax = 1.0; - if (xww + xwn > xwMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xwMax *= 1.02; - - // if the sum of the mole fractions is larger than - // 100%, wetting phase appears - if (xww + xwn > xwMax) - { - // wetting phase appears - std::cout << "wetting phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xww + xwn: " - << xww + xwn << std::endl; - newPhasePresence = bothPhases; - if (formulation == pnsw) - globalSol[dofIdxGlobal][switchIdx] = 0.0; - else if (formulation == pwsn) - globalSol[dofIdxGlobal][switchIdx] = 1.0; - } - } - else if (phasePresence == wPhaseOnly) - { - // calculate fractions of the partial pressures in the - // hypothetic nonwetting phase - Scalar xnw = volVars.moleFraction(nPhaseIdx, wCompIdx); - Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); - - Scalar xgMax = 1.0; - if (xnw + xnn > xgMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xgMax *= 1.02; - - // if the sum of the mole fractions is larger than - // 100%, nonwetting phase appears - if (xnw + xnn > xgMax) - { - // nonwetting phase appears - std::cout << "nonwetting phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xnw + xnn: " - << xnw + xnn << std::endl; - newPhasePresence = bothPhases; - if (formulation == pnsw) - globalSol[dofIdxGlobal][switchIdx] = 0.999; - else if (formulation == pwsn) - globalSol[dofIdxGlobal][switchIdx] = 0.001; - } - } - else if (phasePresence == bothPhases) - { - Scalar Smin = 0.0; - if (staticDat_[dofIdxGlobal].wasSwitched) - Smin = -0.01; - - if (volVars.saturation(nPhaseIdx) <= Smin) - { - wouldSwitch = true; - // nonwetting phase disappears - std::cout << "Nonwetting phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sn: " - << volVars.saturation(nPhaseIdx) << std::endl; - newPhasePresence = wPhaseOnly; - - if(useMoles) // mole-fraction formulation - { - globalSol[dofIdxGlobal][switchIdx] - = volVars.moleFraction(wPhaseIdx, nCompIdx); - } - else // mass-fraction formulation - { - globalSol[dofIdxGlobal][switchIdx] - = volVars.massFraction(wPhaseIdx, nCompIdx); - } - } - else if (volVars.saturation(wPhaseIdx) <= Smin) - { - wouldSwitch = true; - // wetting phase disappears - std::cout << "Wetting phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sw: " - << volVars.saturation(wPhaseIdx) << std::endl; - newPhasePresence = nPhaseOnly; - - if(useMoles) // mole-fraction formulation - { - globalSol[dofIdxGlobal][switchIdx] - = volVars.moleFraction(nPhaseIdx, wCompIdx); - } - else // mass-fraction formulation - { - globalSol[dofIdxGlobal][switchIdx] - = volVars.massFraction(nPhaseIdx, wCompIdx); - } - } - } - - staticDat_[dofIdxGlobal].phasePresence = newPhasePresence; - staticDat_[dofIdxGlobal].wasSwitched = wouldSwitch; - return phasePresence != newPhasePresence; - } - -protected: - // parameters given in constructor - std::vector<StaticVars> staticDat_; - bool switchFlag_; -}; - -} - -#include "2p2cpropertydefaults.hh" +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #endif diff --git a/dumux/implicit/2p2c/2p2cnewtoncontroller.hh b/dumux/implicit/2p2c/2p2cnewtoncontroller.hh index 782fee3b7b..a07f5ac55c 100644 --- a/dumux/implicit/2p2c/2p2cnewtoncontroller.hh +++ b/dumux/implicit/2p2c/2p2cnewtoncontroller.hh @@ -1,104 +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 A two-phase two-component specific controller for the Newton solver. - */ -#ifndef DUMUX_2P2C_NEWTON_CONTROLLER_HH -#define DUMUX_2P2C_NEWTON_CONTROLLER_HH +#ifndef DUMUX_2P2C_NEWTON_CONTROLLER_HH_OLD +#define DUMUX_2P2C_NEWTON_CONTROLLER_HH_OLD -#include "2p2cproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/newtoncontroller.hh instead -#include <dumux/nonlinear/newtoncontroller.hh> - -namespace Dumux { - -/*! - * \ingroup Newton - * \ingroup TwoPTwoCModel - * \brief A two-phase two-component specific controller for the Newton solver. - * - * This controller 'knows' what a 'physically meaningful' solution is - * which allows the Newton method to abort earlier if the solution is - * way out of bounds. - */ -template <class TypeTag> -class TwoPTwoCNewtonController : public NewtonController<TypeTag> -{ - typedef NewtonController<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - -public: - TwoPTwoCNewtonController(const Problem &problem) - : ParentType(problem) - {} - - /*! - * \brief Suggest a new time step size based either on the number of Newton - * iterations required or on the variable switch - * - * \param uCurrentIter The current global solution vector - * \param uLastIter The previous global solution vector - * - */ - void newtonEndStep(SolutionVector &uCurrentIter, - const SolutionVector &uLastIter) - { - int succeeded; - try { - // call the method of the base class - this->method().model().updateStaticData(uCurrentIter, uLastIter); - ParentType::newtonEndStep(uCurrentIter, uLastIter); - - succeeded = 1; - if (this->gridView_().comm().size() > 1) - succeeded = this->gridView_().comm().min(succeeded); - } - catch (Dumux::NumericalProblem &e) - { - std::cout << "rank " << this->problem_().gridView().comm().rank() - << " caught an exception while updating:" << e.what() - << "\n"; - succeeded = 0; - if (this->gridView_().comm().size() > 1) - succeeded = this->gridView_().comm().min(succeeded); - } - - if (!succeeded) { - DUNE_THROW(NumericalProblem, - "A process did not succeed in linearizing the system"); - } - } - - /*! - * \brief Returns true if the current solution can be considered to - * be accurate enough - */ - bool newtonConverged() - { - if (this->method().model().switched()) - return false; - - return ParentType::newtonConverged(); - } -}; -} +#include <dumux/porousmediumflow/2p2c/implicit/newtoncontroller.hh> #endif diff --git a/dumux/implicit/2p2c/2p2cproperties.hh b/dumux/implicit/2p2c/2p2cproperties.hh index 1d0a6811bd..dae800ae1b 100644 --- a/dumux/implicit/2p2c/2p2cproperties.hh +++ b/dumux/implicit/2p2c/2p2cproperties.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 TwoPTwoCModel - * - * \file - * - * \brief Defines the properties required for the two-phase two-component - * fully implicit model. - */ -#ifndef DUMUX_2P2C_PROPERTIES_HH -#define DUMUX_2P2C_PROPERTIES_HH +#ifndef DUMUX_2P2C_PROPERTIES_HH_OLD +#define DUMUX_2P2C_PROPERTIES_HH_OLD -#include <dumux/implicit/box/properties.hh> -#include <dumux/implicit/cellcentered/properties.hh> -#include<dumux/porousmediumflow/nonisothermal/implicit/properties.hh> +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/properties.hh instead -namespace Dumux -{ - -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tags for the implicit isothermal two-phase two-component problems -NEW_TYPE_TAG(TwoPTwoC); -NEW_TYPE_TAG(BoxTwoPTwoC, INHERITS_FROM(BoxModel, TwoPTwoC)); -NEW_TYPE_TAG(CCTwoPTwoC, INHERITS_FROM(CCModel, TwoPTwoC)); - -//! The type tags for the corresponding non-isothermal problems -NEW_TYPE_TAG(TwoPTwoCNI, INHERITS_FROM(TwoPTwoC, NonIsothermal)); -NEW_TYPE_TAG(BoxTwoPTwoCNI, INHERITS_FROM(BoxModel, TwoPTwoCNI)); -NEW_TYPE_TAG(CCTwoPTwoCNI, INHERITS_FROM(CCModel, TwoPTwoCNI)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// - -NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system -NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system -NEW_PROP_TAG(Indices); //!< Enumerations for the model -NEW_PROP_TAG(Formulation); //!< The formulation of the model -NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters -NEW_PROP_TAG(FluidSystem); //!< The type of the multi-component relations -NEW_PROP_TAG(FluidState); //!< The type of the 2p2c fluid state - -NEW_PROP_TAG(MaterialLaw); //!< The material law which ought to be used (extracted from the spatial parameters) -NEW_PROP_TAG(MaterialLawParams); //!< The parameters of the material law (extracted from the spatial parameters) -NEW_PROP_TAG(EffectiveDiffusivityModel); //!< The employed model for the computation of the effective diffusivity - -NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem -NEW_PROP_TAG(UseMoles); //!< Defines whether mole (true) or mass (false) fractions are used -NEW_PROP_TAG(UseConstraintSolver); //!< Determines whether the constraint solver should be used - -NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The value of the upwind weight for the mass conservation equations -NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation -NEW_PROP_TAG(ReplaceCompEqIdx); //!< The index of the total mass balance equation, - //!< if one component balance is replaced (ReplaceCompEqIdx < NumComponents) -NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the VTK output -NEW_PROP_TAG(BaseFluxVariables); //!< The base flux variables -NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient -} -} +#include <dumux/porousmediumflow/2p2c/implicit/properties.hh> #endif diff --git a/dumux/implicit/2p2c/2p2cpropertydefaults.hh b/dumux/implicit/2p2c/2p2cpropertydefaults.hh index e7c1fbe620..bfc725354a 100644 --- a/dumux/implicit/2p2c/2p2cpropertydefaults.hh +++ b/dumux/implicit/2p2c/2p2cpropertydefaults.hh @@ -1,232 +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 TwoPTwoCModel - * \file - * - * \brief Defines default values for most properties required by the - * two-phase two-component fully implicit model. - */ -#ifndef DUMUX_2P2C_PROPERTY_DEFAULTS_HH -#define DUMUX_2P2C_PROPERTY_DEFAULTS_HH +#ifndef DUMUX_2P2C_PROPERTY_DEFAULTS_HH_OLD +#define DUMUX_2P2C_PROPERTY_DEFAULTS_HH_OLD -#include "2p2cproperties.hh" -#include "2p2cmodel.hh" -#include "2p2cindices.hh" -#include "2p2cfluxvariables.hh" -#include "2p2cvolumevariables.hh" -#include "2p2clocalresidual.hh" -#include "2p2cnewtoncontroller.hh" +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/propertydefaults.hh instead -#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> -#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> -#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> -#include <dumux/material/spatialparams/implicitspatialparams.hh> -#include <dumux/material/fluidmatrixinteractions/2p/thermalconductivitysomerton.hh> - -namespace Dumux -{ - -namespace Properties { -////////////////////////////////////////////////////////////////// -// Property values -////////////////////////////////////////////////////////////////// - -/*! - * \brief Set the property for the number of components. - * - * We just forward the number from the fluid system and use a static - * assert to make sure it is 2. - */ -SET_PROP(TwoPTwoC, NumComponents) -{ - private: - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - - public: - static const int value = FluidSystem::numComponents; - - static_assert(value == 2, - "Only fluid systems with 2 components are supported by the 2p-2c model!"); -}; - -/*! - * \brief Set the property for the number of fluid phases. - * - * We just forward the number from the fluid system and use a static - * assert to make sure it is 2. - */ -SET_PROP(TwoPTwoC, NumPhases) -{ - private: - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - - public: - static const int value = FluidSystem::numPhases; - static_assert(value == 2, - "Only fluid systems with 2 phases are supported by the 2p-2c model!"); -}; - -/*! - * \brief The fluid state which is used by the volume variables to - * store the thermodynamic state. This should be chosen - * appropriately for the model ((non-)isothermal, equilibrium, ...). - * This can be done in the problem. - */ -SET_PROP(TwoPTwoC, 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 the number of equations to 2 -SET_INT_PROP(TwoPTwoC, NumEq, 2); - -//! Set the default formulation to pw-sn -SET_INT_PROP(TwoPTwoC, - Formulation, - TwoPTwoCFormulation::pwsn); - -//! Set as default that no component mass balance is replaced by the total mass balance -SET_INT_PROP(TwoPTwoC, ReplaceCompEqIdx, 2); - -//! Set the property for the material parameters by extracting it from the material law. -SET_PROP(TwoPTwoC, MaterialLawParams) -{ - private: - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - - public: - typedef typename MaterialLaw::Params type; -}; - -//! Use the 2p2c local residual operator -SET_TYPE_PROP(TwoPTwoC, - LocalResidual, - TwoPTwoCLocalResidual<TypeTag>); - -//! Use the 2p2c Newton controller -SET_TYPE_PROP(TwoPTwoC, NewtonController, TwoPTwoCNewtonController<TypeTag>); - -//! Use the 2p2c model -SET_TYPE_PROP(TwoPTwoC, Model, TwoPTwoCModel<TypeTag>); - -//! Use the 2p2c VolumeVariables -SET_TYPE_PROP(TwoPTwoC, VolumeVariables, TwoPTwoCVolumeVariables<TypeTag>); - -//! Use the 2p2c FluxVariables -SET_TYPE_PROP(TwoPTwoC, FluxVariables, TwoPTwoCFluxVariables<TypeTag>); - -//! Set the BaseFluxVariables to realize Darcy flow -SET_TYPE_PROP(TwoPTwoC, BaseFluxVariables, ImplicitDarcyFluxVariables<TypeTag>); - -//! Set the upwind weight for the mass conservation equations -SET_SCALAR_PROP(TwoPTwoC, ImplicitMassUpwindWeight, 1.0); - -//! Set default mobility upwind weight to 1.0, i.e. fully upwind -SET_SCALAR_PROP(TwoPTwoC, ImplicitMobilityUpwindWeight, 1.0); - -//! Set the indices required by the isothermal 2p2c -SET_PROP(TwoPTwoC, Indices) -{ private: - enum { Formulation = GET_PROP_VALUE(TypeTag, Formulation) }; - public: - typedef TwoPTwoCIndices<TypeTag, Formulation, 0> type; -}; - -//! Use the ImplicitSpatialParams by default -SET_TYPE_PROP(TwoPTwoC, SpatialParams, ImplicitSpatialParams<TypeTag>); - -//! Use the model after Millington (1961) for the effective diffusivity -SET_PROP(TwoPTwoC, EffectiveDiffusivityModel) -{ private : - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - public: - typedef DiffusivityMillingtonQuirk<Scalar> type; -}; - -//! Disable velocity output by default -SET_BOOL_PROP(TwoPTwoC, VtkAddVelocity, false); - -//! Enable gravity by default -SET_BOOL_PROP(TwoPTwoC, ProblemEnableGravity, true); - -//! Use mole fractions in the balance equations by default -SET_BOOL_PROP(TwoPTwoC, UseMoles, true); - -//! Determines whether the constraint solver is used -SET_BOOL_PROP(TwoPTwoC, UseConstraintSolver, true); - -//! Set default value for the Forchheimer coefficient -// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. -// Actually the Forchheimer coefficient is also a function of the dimensions of the -// porous medium. Taking it as a constant is only a first approximation -// (Nield, Bejan, Convection in porous media, 2006, p. 10) -SET_SCALAR_PROP(TwoPTwoC, SpatialParamsForchCoeff, 0.55); - -//! Somerton is used as default model to compute the effective thermal heat conductivity -SET_PROP(TwoPTwoCNI, ThermalConductivityModel) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; -public: - typedef ThermalConductivitySomerton<Scalar, Indices> type; -}; - -//! temperature is already written by the isothermal model -SET_BOOL_PROP(TwoPTwoCNI, NiOutputLevel, 0); - -////////////////////////////////////////////////////////////////// -// Property values for isothermal model required for the general non-isothermal model -////////////////////////////////////////////////////////////////// - -// set isothermal Model -SET_TYPE_PROP(TwoPTwoCNI, IsothermalModel, TwoPTwoCModel<TypeTag>); - -// set isothermal FluxVariables -SET_TYPE_PROP(TwoPTwoCNI, IsothermalFluxVariables, TwoPTwoCFluxVariables<TypeTag>); - -//set isothermal VolumeVariables -SET_TYPE_PROP(TwoPTwoCNI, IsothermalVolumeVariables, TwoPTwoCVolumeVariables<TypeTag>); - -//set isothermal LocalResidual -SET_TYPE_PROP(TwoPTwoCNI, IsothermalLocalResidual, TwoPTwoCLocalResidual<TypeTag>); - -//set isothermal Indices -SET_PROP(TwoPTwoCNI, IsothermalIndices) -{ -private: - enum { Formulation = GET_PROP_VALUE(TypeTag, Formulation) }; -public: - typedef TwoPTwoCIndices<TypeTag, Formulation, 0> type; -}; - -//set isothermal NumEq -SET_INT_PROP(TwoPTwoCNI, IsothermalNumEq, 2); - -} - -} +#include <dumux/porousmediumflow/2p2c/implicit/propertydefaults.hh> #endif diff --git a/dumux/implicit/2p2c/2p2cvolumevariables.hh b/dumux/implicit/2p2c/2p2cvolumevariables.hh index 65ab5a884f..a71c4a04d6 100644 --- a/dumux/implicit/2p2c/2p2cvolumevariables.hh +++ b/dumux/implicit/2p2c/2p2cvolumevariables.hh @@ -1,621 +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 Contains the quantities which are constant within a - * finite volume in the two-phase two-component model. - */ -#ifndef DUMUX_2P2C_VOLUME_VARIABLES_HH -#define DUMUX_2P2C_VOLUME_VARIABLES_HH +#ifndef DUMUX_2P2C_VOLUME_VARIABLES_HH_OLD +#define DUMUX_2P2C_VOLUME_VARIABLES_HH_OLD -#include <dumux/implicit/model.hh> -#include <dumux/material/fluidstates/compositionalfluidstate.hh> -#include <dumux/material/constraintsolvers/computefromreferencephase.hh> -#include <dumux/material/constraintsolvers/misciblemultiphasecomposition.hh> -#include "2p2cproperties.hh" -#include "2p2cindices.hh" +#warning this header is deprecated, use dumux/porousmediumflow/2p2c/implicit/volumevariables.hh instead -namespace Dumux -{ - -/*! - * \ingroup TwoPTwoCModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are constant within a - * finite volume in the two-phase two-component model. - */ -template <class TypeTag> -class TwoPTwoCVolumeVariables : public ImplicitVolumeVariables<TypeTag> -{ - typedef ImplicitVolumeVariables<TypeTag> ParentType; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; - enum { - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents) - }; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - wCompIdx = Indices::wCompIdx, - nCompIdx = Indices::nCompIdx, - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx - }; - - // present phases - enum { - wPhaseOnly = Indices::wPhaseOnly, - nPhaseOnly = Indices::nPhaseOnly, - bothPhases = Indices::bothPhases - }; - - // formulations - enum { - formulation = GET_PROP_VALUE(TypeTag, Formulation), - pwsn = TwoPTwoCFormulation::pwsn, - pnsw = TwoPTwoCFormulation::pnsw - }; - - // primary variable indices - enum { - switchIdx = Indices::switchIdx, - pressureIdx = Indices::pressureIdx - }; - - 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 typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef Dumux::MiscibleMultiPhaseComposition<Scalar, FluidSystem> MiscibleMultiPhaseComposition; - static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); - static const bool useConstraintSolver = GET_PROP_VALUE(TypeTag, UseConstraintSolver); - static_assert(useMoles || (!useMoles && useConstraintSolver), - "if UseMoles is set false, UseConstraintSolver has to be set to true"); - typedef Dumux::ComputeFromReferencePhase<Scalar, FluidSystem> ComputeFromReferencePhase; - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - -public: - - typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; - - /*! - * \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); - - completeFluidState(priVars, problem, element, fvGeometry, scvIdx, fluidState_, isOldSol); - - ///////////// - // calculate the remaining quantities - ///////////// - const MaterialLawParams &materialParams = - problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); - - // Second instance of a parameter cache. - // Could be avoided if diffusion coefficients also - // became part of the fluid state. - typename FluidSystem::ParameterCache paramCache; - paramCache.updateAll(fluidState_); - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - - - // relative permeabilities - Scalar kr; - if (phaseIdx == wPhaseIdx) - kr = MaterialLaw::krw(materialParams, saturation(wPhaseIdx)); - else // ATTENTION: krn requires the wetting phase saturation - // as parameter! - kr = MaterialLaw::krn(materialParams, saturation(wPhaseIdx)); - relativePermeability_[phaseIdx] = kr; - Valgrind::CheckDefined(relativePermeability_[phaseIdx]); - - // binary diffusion coefficients - diffCoeff_[phaseIdx] = - FluidSystem::binaryDiffusionCoefficient(fluidState_, - paramCache, - phaseIdx, - wCompIdx, - nCompIdx); - Valgrind::CheckDefined(diffCoeff_[phaseIdx]); - } - - // porosity - porosity_ = problem.spatialParams().porosity(element, - fvGeometry, - scvIdx); - Valgrind::CheckDefined(porosity_); - - // energy related quantities not contained in the fluid state - asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol); - } - - /*! - * \copydoc ImplicitModel::completeFluidState - * \param isOldSol Specifies whether this is the previous solution or the current one - */ - static void completeFluidState(const PrimaryVariables& priVars, - const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - int scvIdx, - FluidState& fluidState, - bool isOldSol = false) - { - Scalar t = Implementation::temperature_(priVars, problem, element, - fvGeometry, scvIdx); - fluidState.setTemperature(t); - int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); - int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); - - ///////////// - // set the saturations - ///////////// - Scalar sn; - if (phasePresence == nPhaseOnly) - sn = 1.0; - else if (phasePresence == wPhaseOnly) { - sn = 0.0; - } - else if (phasePresence == bothPhases) { - if (formulation == pwsn) - sn = priVars[switchIdx]; - else if (formulation == pnsw) - sn = 1.0 - priVars[switchIdx]; - else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); - } - else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); - fluidState.setSaturation(wPhaseIdx, 1 - sn); - fluidState.setSaturation(nPhaseIdx, sn); - - ///////////// - // set the pressures of the fluid phases - ///////////// - - // calculate capillary pressure - const MaterialLawParams &materialParams = - problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); - Scalar pc = MaterialLaw::pc(materialParams, 1 - sn); - - if (formulation == pwsn) { - fluidState.setPressure(wPhaseIdx, priVars[pressureIdx]); - fluidState.setPressure(nPhaseIdx, priVars[pressureIdx] + pc); - } - else if (formulation == pnsw) { - fluidState.setPressure(nPhaseIdx, priVars[pressureIdx]); - fluidState.setPressure(wPhaseIdx, priVars[pressureIdx] - pc); - } - else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); - - ///////////// - // calculate the phase compositions - ///////////// - typename FluidSystem::ParameterCache paramCache; - - //get the phase pressures and set the fugacity coefficients here if constraintsolver is not used - Scalar pn = 0; - Scalar pw = 0; - - if(!useConstraintSolver) { - if (formulation == pwsn) { - pw = priVars[pressureIdx]; - pn = pw + pc; - } - else { - pn = priVars[pressureIdx]; - pw = pn - pc; - } - - for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { - assert(FluidSystem::isIdealMixture(phaseIdx)); - - for (int compIdx = 0; compIdx < numComponents; ++ compIdx) { - Scalar phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx); - fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi); - } - } - } - - // now comes the tricky part: calculate phase compositions - if (phasePresence == bothPhases) { - // both phases are present, phase compositions are a - // result of the the nonwetting <-> wetting equilibrium. This is - // the job of the "MiscibleMultiPhaseComposition" - // constraint solver - if(useConstraintSolver) { - MiscibleMultiPhaseComposition::solve(fluidState, - paramCache, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - // ... or calculated explicitly this way ... - else { - //get the partial pressure of the main component of the the wetting phase ("H20") within the nonwetting (gas) phase == vapor pressure due to equilibrium - //note that in this case the fugacityCoefficient * pw is the vapor pressure (see implementation in respective fluidsystem) - Scalar partPressH2O = FluidSystem::fugacityCoefficient(fluidState, - wPhaseIdx, - wCompIdx) * pw; - - // get the partial pressure of the main component of the the nonwetting (gas) phase ("Air") - Scalar partPressAir = pn - partPressH2O; - - //calculate the mole fractions of the components within the nonwetting phase - Scalar xnn = partPressAir/pn; - Scalar xnw = partPressH2O/pn; - - // calculate the mole fractions of the components within the wetting phase - //note that in this case the fugacityCoefficient * pw is the Henry Coefficient (see implementation in respective fluidsystem) - Scalar xwn = partPressAir - / (FluidSystem::fugacityCoefficient(fluidState, - wPhaseIdx,nCompIdx) - * pw); - - Scalar xww = 1.0 -xwn; - - //set all mole fractions - fluidState.setMoleFraction(wPhaseIdx, wCompIdx, xww); - fluidState.setMoleFraction(wPhaseIdx, nCompIdx, xwn); - fluidState.setMoleFraction(nPhaseIdx, wCompIdx, xnw); - fluidState.setMoleFraction(nPhaseIdx, nCompIdx, xnn); - - paramCache.updateComposition(fluidState, wPhaseIdx); - paramCache.updateComposition(fluidState, nPhaseIdx); - - //set the phase densities - Scalar rhoW = FluidSystem::density(fluidState, paramCache, wPhaseIdx); - Scalar rhoN = FluidSystem::density(fluidState, paramCache, nPhaseIdx); - - fluidState.setDensity(wPhaseIdx, rhoW); - fluidState.setDensity(nPhaseIdx, rhoN); - } - } - else if (phasePresence == nPhaseOnly) { - // only the nonwetting phase is present, i.e. nonwetting phase - // composition is stored explicitly. - if(useMoles) - { - fluidState.setMoleFraction(nPhaseIdx, nCompIdx, 1 - priVars[switchIdx]); - fluidState.setMoleFraction(nPhaseIdx, wCompIdx, priVars[switchIdx]); - } - else - { - // setMassFraction() has only to be called 1-numComponents times - fluidState.setMassFraction(nPhaseIdx, wCompIdx, priVars[switchIdx]); - } - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). This is the job - // of the "ComputeFromReferencePhase" constraint solver - if (useConstraintSolver) { - ComputeFromReferencePhase::solve(fluidState, - paramCache, - nPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - // ... or calculated explicitly this way ... - else { - // note that the water phase is actually not existing! - // thus, this is used as phase switch criterion - Scalar xnw = priVars[switchIdx]; - Scalar xnn = 1.0 -xnw; - - //first, xww: - // xnw * pn = "actual" (hypothetical) vapor pressure - // fugacityCoefficient * pw = vapor pressure given by thermodynamic conditions - // Here, xww is not actually the mole fraction of water in the wetting phase - // xww is only the ratio of "actual" vapor pressure / "thermodynamic" vapor pressure - // If xww > 1 : gas is over-saturated with water vapor, - // condensation takes place (see switch criterion in model) - Scalar xww = xnw * pn - / (FluidSystem::fugacityCoefficient(fluidState, - wPhaseIdx,wCompIdx) - * pw); - - // now, xwn: - //partialPressure / xwn = Henry - //partialPressure = xnn * pn - //xwn = xnn * pn / Henry - // Henry = fugacityCoefficient * pw - Scalar xwn = xnn * pn / (FluidSystem::fugacityCoefficient(fluidState, - wPhaseIdx,nCompIdx) - * pw); - - fluidState.setMoleFraction(wPhaseIdx, wCompIdx, xww); - fluidState.setMoleFraction(wPhaseIdx, nCompIdx, xwn); - - paramCache.updateComposition(fluidState, wPhaseIdx); - paramCache.updateComposition(fluidState, nPhaseIdx); - - Scalar rhoW = FluidSystem::density(fluidState, paramCache, wPhaseIdx); - Scalar rhoN = FluidSystem::density(fluidState, paramCache, nPhaseIdx); - - fluidState.setDensity(wPhaseIdx, rhoW); - fluidState.setDensity(nPhaseIdx, rhoN); - } - } - else if (phasePresence == wPhaseOnly) { - // only the wetting phase is present, i.e. wetting phase - // composition is stored explicitly. - if(useMoles) // mole-fraction formulation - { - fluidState.setMoleFraction(wPhaseIdx, wCompIdx, 1-priVars[switchIdx]); - fluidState.setMoleFraction(wPhaseIdx, nCompIdx, priVars[switchIdx]); - } - else // mass-fraction formulation - { - // setMassFraction() has only to be called 1-numComponents times - fluidState.setMassFraction(wPhaseIdx, nCompIdx, priVars[switchIdx]); - } - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). This is the job - // of the "ComputeFromReferencePhase" constraint solver - if (useConstraintSolver) { - ComputeFromReferencePhase::solve(fluidState, - paramCache, - wPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - // ... or calculated explicitly this way ... - else { - // note that the gas phase is actually not existing! - // thus, this is used as phase switch criterion - Scalar xwn = priVars[switchIdx]; - - //first, xnw: - //psteam = xnw * pn = partial pressure of water in gas phase - //psteam = fugacityCoefficient * pw - Scalar xnw = (FluidSystem::fugacityCoefficient(fluidState, - wPhaseIdx,wCompIdx) - * pw) / pn ; - - //now, xnn: - // xwn = partialPressure / Henry - // partialPressure = pn * xnn - // xwn = pn * xnn / Henry - // xnn = xwn * Henry / pn - // Henry = fugacityCoefficient * pw - Scalar xnn = xwn * (FluidSystem::fugacityCoefficient(fluidState, - wPhaseIdx,nCompIdx) - * pw) / pn ; - - fluidState.setMoleFraction(nPhaseIdx, nCompIdx, xnn); - fluidState.setMoleFraction(nPhaseIdx, wCompIdx, xnw); - - paramCache.updateComposition(fluidState, wPhaseIdx); - paramCache.updateComposition(fluidState, nPhaseIdx); - - Scalar rhoW = FluidSystem::density(fluidState, paramCache, wPhaseIdx); - Scalar rhoN = FluidSystem::density(fluidState, paramCache, nPhaseIdx); - - fluidState.setDensity(wPhaseIdx, rhoW); - fluidState.setDensity(nPhaseIdx, rhoN); - } - } - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - //set the viscosity here if constraintsolver is not used - if(!useConstraintSolver) { - const Scalar mu = - FluidSystem::viscosity(fluidState, - paramCache, - phaseIdx); - fluidState.setViscosity(phaseIdx,mu); - } - // compute and set the enthalpy - Scalar h = Implementation::enthalpy_(fluidState, paramCache, phaseIdx); - fluidState.setEnthalpy(phaseIdx, h); - } - } - - - /*! - * \brief Returns the phase state within the control volume. - */ - const FluidState &fluidState() const - { return fluidState_; } - - /*! - * \brief Returns the saturation of a given phase within - * the control volume in \f$[-]\f$. - * - * \param phaseIdx The phase index - */ - Scalar saturation(const int phaseIdx) const - { return fluidState_.saturation(phaseIdx); } - - /*! - * \brief Returns the mass fraction of a given component in a - * given phase within the control volume in \f$[-]\f$. - * - * \param phaseIdx The phase index - * \param compIdx The component index - */ - Scalar massFraction(const int phaseIdx, const int compIdx) const - { return fluidState_.massFraction(phaseIdx, compIdx); } - - /*! - * \brief Returns the mole fraction of a given component in a - * given phase within the control volume in \f$[-]\f$. - * - * \param phaseIdx The phase index - * \param compIdx The component index - */ - Scalar moleFraction(const int phaseIdx, const int compIdx) const - { return fluidState_.moleFraction(phaseIdx, compIdx); } - - /*! - * \brief Returns the mass density of a given phase within the - * control volume in \f$[kg/m^3]\f$. - * - * \param phaseIdx The phase index - */ - Scalar density(const int phaseIdx) const - { return fluidState_.density(phaseIdx); } - - /*! - * \brief Returns the dynamic viscosity of the fluid within the - * control volume in \f$\mathrm{[Pa s]}\f$. - * - * \param phaseIdx The phase index - */ - Scalar viscosity(const int phaseIdx) const - { return fluidState_.viscosity(phaseIdx); } - - /*! - * \brief Returns the mass density of a given phase within the - * control volume in \f$[mol/m^3]\f$. - * - * \param phaseIdx The phase index - */ - Scalar molarDensity(const int phaseIdx) const - { return fluidState_.density(phaseIdx) / fluidState_.averageMolarMass(phaseIdx); } - - /*! - * \brief Returns the effective pressure of a given phase within - * the control volume in \f$[kg/(m*s^2)=N/m^2=Pa]\f$. - * - * \param phaseIdx The phase index - */ - Scalar pressure(const int phaseIdx) const - { return fluidState_.pressure(phaseIdx); } - - /*! - * \brief Returns temperature within the control volume in \f$[K]\f$. - * - * Note that we assume thermodynamic equilibrium, i.e. the - * temperature of the rock matrix and of all fluid phases are - * identical. - */ - Scalar temperature() const - { return fluidState_.temperature(/*phaseIdx=*/0); } - - /*! - * \brief Returns the relative permeability of a given phase within - * the control volume in \f$[-]\f$. - * - * \param phaseIdx The phase index - */ - Scalar relativePermeability(const int phaseIdx) const - { - return relativePermeability_[phaseIdx]; - } - - /*! - * \brief Returns the effective mobility of a given phase within - * the control volume in \f$[s*m/kg]\f$. - * - * \param phaseIdx The phase index - */ - Scalar mobility(const int phaseIdx) const - { - return relativePermeability_[phaseIdx]/fluidState_.viscosity(phaseIdx); - } - - /*! - * \brief Returns the effective capillary pressure within the control volume - * in \f$[kg/(m*s^2)=N/m^2=Pa]\f$. - */ - Scalar capillaryPressure() const - { return fluidState_.pressure(nPhaseIdx) - fluidState_.pressure(wPhaseIdx); } - - /*! - * \brief Returns the average porosity within the control volume in \f$[-]\f$. - */ - Scalar porosity() const - { return porosity_; } - - /*! - * \brief Returns the binary diffusion coefficients for a phase in \f$[m^2/s]\f$. - */ - Scalar diffCoeff(const int phaseIdx) const - { return diffCoeff_[phaseIdx]; } - - -protected: - static Scalar temperature_(const PrimaryVariables &priVars, - const Problem& problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int scvIdx) - { - return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); - } - - template<class ParameterCache> - static Scalar enthalpy_(const FluidState& fluidState, - const ParameterCache& paramCache, - const int phaseIdx) - { - return 0; - } - - /*! - * \brief Called by update() to compute the energy related quantities - */ - void updateEnergy_(const PrimaryVariables &sol, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx, - bool isOldSol) - { } - - Scalar porosity_; //!< Effective porosity within the control volume - Scalar relativePermeability_[numPhases]; //!< Relative permeability within the control volume - Scalar diffCoeff_[numPhases]; //!< Binary diffusion coefficients for the phases - FluidState fluidState_; - -private: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } - - -}; - -} // end namespace +#include <dumux/porousmediumflow/2p2c/implicit/volumevariables.hh> #endif diff --git a/dumux/implicit/2pnc/2pncfluxvariables.hh b/dumux/implicit/2pnc/2pncfluxvariables.hh index 541db7b224..ce450cea11 100644 --- a/dumux/implicit/2pnc/2pncfluxvariables.hh +++ b/dumux/implicit/2pnc/2pncfluxvariables.hh @@ -1,415 +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 Contains the data which is required to calculate - * all fluxes of components over a face of a finite volume for - * the two-phase two-component model fully implicit model. - */ -#ifndef DUMUX_2PNC_FLUX_VARIABLES_HH -#define DUMUX_2PNC_FLUX_VARIABLES_HH +#ifndef DUMUX_2PNC_FLUX_VARIABLES_HH_OLD +#define DUMUX_2PNC_FLUX_VARIABLES_HH_OLD -#include <dumux/common/math.hh> -#include <dumux/common/spline.hh> +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/fluxvariables.hh instead -#include "2pncproperties.hh" - -namespace Dumux -{ -/*! - * \ingroup TwoPNCModel - * \ingroup ImplicitFluxVariables - * \brief Contains the data which is required to calculate - * all fluxes of components over a face of a finite volume for - * the two-phase n-component fully implicit model. - * - * This means pressure and concentration gradients, phase densities at - * the integration point, etc. - */ - -template <class TypeTag> -class TwoPNCFluxVariables : public GET_PROP_TYPE(TypeTag, BaseFluxVariables) -{ - typedef typename GET_PROP_TYPE(TypeTag, BaseFluxVariables) BaseFluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - - typedef typename GridView::ctype CoordScalar; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - - enum { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld, - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - }; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; -// typedef typename FVElementGeometry::SubControlVolume SCV; - typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; - - typedef Dune::FieldVector<CoordScalar, dimWorld> DimVector; - typedef Dune::FieldMatrix<CoordScalar, dim, dim> DimMatrix; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - wPhaseIdx = FluidSystem::wPhaseIdx, - nPhaseIdx = FluidSystem::nPhaseIdx, - wCompIdx = FluidSystem::wCompIdx, - }; - -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 sub-control-volume face - * \param elemVolVars The volume variables of the current element - * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face - */ - TwoPNCFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : BaseFluxVariables(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) - { - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - density_[phaseIdx] = Scalar(0); - molarDensity_[phaseIdx] = Scalar(0); - potentialGrad_[phaseIdx] = Scalar(0); - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - massFractionGrad_[phaseIdx][compIdx] = Scalar(0); - moleFractionGrad_[phaseIdx][compIdx] = Scalar(0); - } - } - calculateGradients_(problem, element, elemVolVars); - calculateVelocities_(problem, element, elemVolVars); - calculateporousDiffCoeff_(problem, element, elemVolVars); - }; - -protected: - void calculateGradients_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - // calculate gradients - DimVector tmp(0.0); - for (int idx = 0; - idx < this->fvGeometry_.numScv; - idx++) // loop over adjacent vertices - { - // FE gradient at vertex idx - const DimVector &feGrad = face().grad[idx]; - - // compute sum of pressure gradients for each phase - for (int phaseIdx = 0; phaseIdx < numPhases; phaseIdx++) - { - // the pressure gradient - tmp = feGrad; - tmp *= elemVolVars[idx].pressure(phaseIdx); //FE grad times phase pressure - potentialGrad_[phaseIdx] += tmp; - } - - // the concentration gradient of the non-wetting - // component in the wetting phase - - for(int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - for(int compIdx = 0; compIdx < numComponents; ++compIdx) - { - if(compIdx != phaseIdx) //No grad is needed for this case - { - tmp = feGrad; - tmp *= elemVolVars[idx].massFraction(phaseIdx, compIdx); - massFractionGrad_[phaseIdx][compIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[idx].moleFraction(phaseIdx, compIdx); - moleFractionGrad_[phaseIdx][compIdx] += tmp; - } - } - } - } - - // correct the pressure gradients by the hydrostatic - // pressure due to gravity - for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) - { - int i = face().i; - int j = face().j; - Scalar fI = rhoFactor_(phaseIdx, i, elemVolVars); - Scalar fJ = rhoFactor_(phaseIdx, j, elemVolVars); - if (fI + fJ <= 0) - fI = fJ = 0.5; // doesn't matter because no phase is - // present in both cells! - density_[phaseIdx] = - (fI*elemVolVars[i].density(phaseIdx) + - fJ*elemVolVars[j].density(phaseIdx)) - / - (fI + fJ); - // phase density - molarDensity_[phaseIdx] - = - (fI*elemVolVars[i].molarDensity(phaseIdx) + - fJ*elemVolVars[j].molarDensity(phaseIdx)) - / - (fI + fJ); //arithmetic averaging - - tmp = problem.gravity(); - tmp *= density_[phaseIdx]; - - potentialGrad_[phaseIdx] -= tmp; - } - } - - Scalar rhoFactor_(int phaseIdx, int scvIdx, const ElementVolumeVariables &vDat) - { - - static const Scalar eps = 1e-2; - const Scalar sat = vDat[scvIdx].density(phaseIdx); - if (sat > eps) - return 0.5; - if (sat <= 0) - return 0; - - static const Dumux::Spline<Scalar> sp(0, eps, // x0, x1 - 0, 0.5, // y0, y1 - 0, 0); // m0, m1 - return sp.eval(sat); - } - - void calculateVelocities_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - const SpatialParams &spatialParams = problem.spatialParams(); - // multiply the pressure potential with the intrinsic - // permeability - DimMatrix K(0.0); - - for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) - { - auto K_i = spatialParams.intrinsicPermeability(element,this->fvGeometry_,face().i); - //K_i *= volVarsI.permFactor(); - - auto K_j = spatialParams.intrinsicPermeability(element,this->fvGeometry_,face().j); - //K_j *= volVarsJ.permFactor(); - - spatialParams.meanK(K,K_i,K_j); - - K.mv(potentialGrad_[phaseIdx], Kmvp_[phaseIdx]); - KmvpNormal_[phaseIdx] = - (Kmvp_[phaseIdx] * face().normal); - } - - // set the upstream and downstream vertices - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - upstreamIdx_[phaseIdx] = face().i; - downstreamIdx_[phaseIdx] = face().j; - - if (KmvpNormal_[phaseIdx] < 0) { - std::swap(upstreamIdx_[phaseIdx], - downstreamIdx_[phaseIdx]); - } - } - } - - void calculateporousDiffCoeff_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - const VolumeVariables &volVarsI = elemVolVars[face().i]; - const VolumeVariables &volVarsJ = elemVolVars[face().j]; - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - /* If there is no phase saturation on either side of the face - * no diffusion takes place */ - - if (volVarsI.saturation(phaseIdx) <= 0 || - volVarsJ.saturation(phaseIdx) <= 0) - { - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - porousDiffCoeff_[phaseIdx][compIdx] = 0.0; - } - } - - else - { - // calculate tortuosity at the nodes i and j needed - // for porous media diffusion coefficient - Scalar tauI = 1.0/(volVarsI.porosity() * volVarsI.porosity()) * - pow(volVarsI.porosity() * volVarsI.saturation(phaseIdx), 7.0/3); - - Scalar tauJ = 1.0/(volVarsJ.porosity() * volVarsJ.porosity()) * - pow(volVarsJ.porosity() * volVarsJ.saturation(phaseIdx), 7.0/3); - // Diffusion coefficient in the porous medium - - // -> harmonic mean - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - if(phaseIdx==compIdx) - porousDiffCoeff_[phaseIdx][compIdx] = 0.0; - else - { - porousDiffCoeff_[phaseIdx][compIdx] = harmonicMean(volVarsI.porosity() * volVarsI.saturation(phaseIdx) * tauI * volVarsI.diffCoeff(phaseIdx, compIdx), - volVarsJ.porosity() * volVarsJ.saturation(phaseIdx) * tauJ * volVarsJ.diffCoeff(phaseIdx, compIdx)); - } - } - } - } - } - -public: - /*! - * \brief Return the pressure potential multiplied with the - * intrinsic permeability which goes from vertex i to - * vertex j. - * - * Note that the length of the face's normal is the area of the - * face, so this is not the actual velocity by the integral of - * the velocity over the face's area. Also note that the phase - * mobility is not yet included here since this would require a - * decision on the upwinding approach (which is done in the - * model and/or local residual file). - * - * \param phaseIdx The phase index - */ - Scalar KmvpNormal(int phaseIdx) const - { return KmvpNormal_[phaseIdx]; } - - /*! - * \brief Return the pressure potential multiplied with the - * intrinsic permeability as vector (for velocity output) - * - * \param phaseIdx The phase index - */ - DimVector Kmvp(int phaseIdx) const - { return Kmvp_[phaseIdx]; } - - /*! - * \brief Return the local index of the upstream control volume - * for a given phase. - * - * \param phaseIdx The phase index - */ - int upstreamIdx(int phaseIdx) const - { return upstreamIdx_[phaseIdx]; } - - /*! - * \brief Return the local index of the downstream control volume - * for a given phase. - * - * \param phaseIdx The phase index - */ - int downstreamIdx(int phaseIdx) const - { return downstreamIdx_[phaseIdx]; } - - /*! - * \brief The binary diffusion coefficient for each fluid phase. - * - * \param phaseIdx The phase index - * \param compIdx The component index - */ - Scalar porousDiffCoeff(int phaseIdx, int compIdx) const - { return porousDiffCoeff_[phaseIdx][compIdx];} - - /*! - * \brief Return density \f$\mathrm{[kg/m^3]}\f$ of a phase at the integration - * point. - * - * \param phaseIdx The phase index - */ - Scalar density(int phaseIdx) const - { return density_[phaseIdx]; } - - /*! - * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ of a phase at the integration - * point. - * - * \param phaseIdx The phase index - */ - Scalar molarDensity(int phaseIdx) const - { return molarDensity_[phaseIdx]; } - - /*! - * \brief The concentration gradient of a component in a phase. - * - * \param phaseIdx The phase index - * \param compIdx The component index - */ - const DimVector &massFractionGrad(int phaseIdx, int compIdx) const - { return massFractionGrad_[phaseIdx][compIdx]; } - - /*! - * \brief The molar concentration gradient of a component in a phase. - * - * \param phaseIdx The phase index - * \param compIdx The component index - */ - const DimVector &moleFractionGrad(int phaseIdx, int compIdx) const - { return moleFractionGrad_[phaseIdx][compIdx]; } - - const SCVFace &face() const - { - if (this->onBoundary_) - return this->fvGeometry_.boundaryFace[this->faceIdx_]; - else - return this->fvGeometry_.subContVolFace[this->faceIdx_]; - } - -protected: - - // gradients - DimVector potentialGrad_[numPhases]; - DimVector massFractionGrad_[numPhases][numComponents]; - DimVector moleFractionGrad_[numPhases][numComponents]; - - // density of each face at the integration point - Scalar density_[numPhases], molarDensity_[numPhases]; - - // intrinsic permeability times pressure potential gradient - DimVector Kmvp_[numPhases]; - // projected on the face normal - Scalar KmvpNormal_[numPhases]; - - // local index of the upwind vertex for each phase - int upstreamIdx_[numPhases]; - // local index of the downwind vertex for each phase - int downstreamIdx_[numPhases]; - - // the diffusion coefficient for the porous medium - Dune::FieldMatrix<Scalar, numPhases, numComponents> porousDiffCoeff_; -}; - -} // end namespace +#include <dumux/porousmediumflow/2pnc/implicit/fluxvariables.hh> #endif diff --git a/dumux/implicit/2pnc/2pncindices.hh b/dumux/implicit/2pnc/2pncindices.hh index 16e55dad8d..309c8c7318 100644 --- a/dumux/implicit/2pnc/2pncindices.hh +++ b/dumux/implicit/2pnc/2pncindices.hh @@ -1,80 +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_2PNC_INDICES_HH_OLD +#define DUMUX_2PNC_INDICES_HH_OLD -/*! - * \file - * \brief Defines the indices required for the two-phase n-component - * fully implicit model. - */ -#ifndef DUMUX_2PNC_INDICES_HH -#define DUMUX_2PNC_INDICES_HH -#include "2pncproperties.hh" -namespace Dumux -{ -/*! - * \ingroup TwoPNCModel - * \ingroup ImplicitIndices - * \brief Enumerates the formulations which the two-phase n-component model accepts. - * - */ -struct TwoPNCFormulation//TODO: This might need to be change similar to 2p2c indices -{ - enum { - plSg, - pgSl, - pnSw = pgSl, - pwSn = plSg - }; -}; +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/indices.hh instead -/*! - * \ingroup TwoPNCModel - * \ingroup ImplicitIndices - * \brief The indices for the isothermal two-phase n-component model. - * - * \tparam PVOffset The first index in a primary variable vector. - */ -template <class TypeTag, int PVOffset = 0> -class TwoPNCIndices -{ - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - -public: - // Phase indices - static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< Index of the wetting phase - static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< Index of the non-wetting phase - // present phases (-> 'pseudo' primary variable) - static const int wPhaseOnly = 1; //!< Only the non-wetting phase is present - static const int nPhaseOnly = 2; //!< Only the wetting phase is present - static const int bothPhases = 3; //!< Both phases are present - - // Primary variable indices - static const int pressureIdx = PVOffset + 0; //!< Index for wetting/non-wetting phase pressure (depending on formulation) in a solution vector - static const int switchIdx = PVOffset + 1; //!< Index of the either the saturation or the mass fraction of the non-wetting/wetting phase - // equation indices - static const int conti0EqIdx = PVOffset + 0; //!< Reference index for mass conservation equations. - static const int contiWEqIdx = conti0EqIdx + FluidSystem::wCompIdx; //!< Index of the mass conservation equation for the wetting phase major component - static const int contiNEqIdx = conti0EqIdx + FluidSystem::nCompIdx; //!< Index of the mass conservation equation for the non-wetting phase major component -}; - -// \} - -} +#include <dumux/porousmediumflow/2pnc/implicit/indices.hh> #endif diff --git a/dumux/implicit/2pnc/2pnclocalresidual.hh b/dumux/implicit/2pnc/2pnclocalresidual.hh index 6cbb065a1f..719ae05878 100644 --- a/dumux/implicit/2pnc/2pnclocalresidual.hh +++ b/dumux/implicit/2pnc/2pnclocalresidual.hh @@ -1,349 +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 Jacobian matrix for problems - * using the two-phase n-component box model. - */ +#ifndef DUMUX_2PNC_LOCAL_RESIDUAL_BASE_HH_OLD +#define DUMUX_2PNC_LOCAL_RESIDUAL_BASE_HH_OLD -#ifndef DUMUX_2PNC_LOCAL_RESIDUAL_BASE_HH -#define DUMUX_2PNC_LOCAL_RESIDUAL_BASE_HH +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/localresidual.hh instead -#include "2pncproperties.hh" -#include "2pncvolumevariables.hh" -#include <dumux/nonlinear/newtoncontroller.hh> - -#include <iostream> -#include <vector> - -namespace Dumux -{ -/*! - * \ingroup TwoPNCModel - * \ingroup ImplicitLocalResidual - * \brief Element-wise calculation of the Jacobian matrix for problems - * using the two-phase n-component fully implicit box model. - * - * This class is used to fill the gaps in ImplicitLocalResidual for the two-phase n-component flow. - */ -template<class TypeTag> -class TwoPNCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) -{ -protected: - typedef TwoPNCLocalResidual<TypeTag> ThisType; - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef BoxLocalResidual<TypeTag> ParentType; - - 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, FluidSystem) FluidSystem; - - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - - typedef CompositionalFluidState<Scalar, FluidSystem> FluidState; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum - { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld, - - numEq = GET_PROP_VALUE(TypeTag, NumEq), - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - - replaceCompEqIdx = GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx), - - pressureIdx = Indices::pressureIdx, - switchIdx = Indices::switchIdx, - - wPhaseIdx = FluidSystem::wPhaseIdx, - nPhaseIdx = FluidSystem::nPhaseIdx, - - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx, - - conti0EqIdx = Indices::conti0EqIdx, - - wPhaseOnly = Indices::wPhaseOnly, - nPhaseOnly = Indices::nPhaseOnly, - bothPhases = Indices::bothPhases, - - plSg = TwoPNCFormulation::plSg, - pgSl = TwoPNCFormulation::pgSl, - formulation = GET_PROP_VALUE(TypeTag, Formulation) - }; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - - - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GridView::ctype CoordScalar; - - -public: - /*! - * \brief Constructor. Sets the upwind weight. - */ - TwoPNCLocalResidual() - { - // 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 storage term of the current solution in a - * single phase. - * - * \param element The element - * \param phaseIdx The index of the fluid phase - */ - void evalPhaseStorage(const Element &element, int phaseIdx) - { - FVElementGeometry fvGeometry; - fvGeometry.update(this->gridView_(), element); - ElementBoundaryTypes bcTypes; - bcTypes.update(this->problem_(), element, fvGeometry); - ElementVolumeVariables volVars; - volVars.update(this->problem_(), element, fvGeometry, false); - - this->residual_.resize(fvGeometry.numScv); - this->residual_ = 0; - - this->elemPtr_ = &element; - this->fvElemGeomPtr_ = &fvGeometry; - this->bcTypesPtr_ = &bcTypes; - this->prevVolVarsPtr_ = 0; - this->curVolVarsPtr_ = &volVars; - evalPhaseStorage_(phaseIdx); - } - - /*! - * \brief Evaluate the amount all conservation quantities - * (e.g. phase mass) within a sub-control volume. - * - * The result should be averaged over the volume (e.g. phase mass - * inside a sub control volume divided by the volume) - * - * \param storage the mass of the component 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]; - - // Compute storage term of all fluid components in the fluid phases - storage = 0; - for (unsigned int phaseIdx = 0; phaseIdx < numPhases /*+ numSPhases*/; ++phaseIdx) - { - //if(phaseIdx< numPhases) - //{ - for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) //H2O, Air, Salt - { - int eqIdx = conti0EqIdx + compIdx; - if (replaceCompEqIdx != eqIdx) - { - storage[eqIdx] += volVars.molarDensity(phaseIdx) - * volVars.saturation(phaseIdx) - * volVars.moleFraction(phaseIdx, compIdx) - * volVars.porosity(); - } - else - { - storage[replaceCompEqIdx] += volVars.molarDensity(phaseIdx) - * volVars.saturation(phaseIdx) - * volVars.porosity(); - } - } - } - Valgrind::CheckDefined(storage); - } - /*! - * \brief Evaluates the total flux of all conservation quantities - * over a face of a sub-control volume. - * - * \param flux The flux over the sub-control-volume face for each component - * \param fIdx The index of the sub-control-volume face - * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face - */ - void computeFlux(PrimaryVariables &flux, const int fIdx, bool onBoundary = false) const - { - FluxVariables fluxVars(this->problem_(), - this->element_(), - this->fvGeometry_(), - fIdx, - this->curVolVars_(), - onBoundary); - - flux = 0; - asImp_()->computeAdvectiveFlux(flux, fluxVars); - asImp_()->computeDiffusiveFlux(flux, fluxVars); - Valgrind::CheckDefined(flux); - } - /*! - * \brief Evaluates the advective mass flux of all components 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 - //////// - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - // 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)); - - for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) - { - // add advective flux of current component in current - // phase - unsigned int eqIdx = conti0EqIdx + compIdx; - - if (eqIdx != replaceCompEqIdx) - { - // upstream vertex - flux[eqIdx] += fluxVars.KmvpNormal(phaseIdx) - * (massUpwindWeight_ - * up.mobility(phaseIdx) - * up.molarDensity(phaseIdx) - * up.moleFraction(phaseIdx, compIdx) - + - (1.0 - massUpwindWeight_) - * dn.mobility(phaseIdx) - * dn.molarDensity(phaseIdx) - * dn.moleFraction(phaseIdx, compIdx)); - - Valgrind::CheckDefined(fluxVars.KmvpNormal(phaseIdx)); - Valgrind::CheckDefined(up.molarDensity(phaseIdx)); - Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); - } - else - { - flux[replaceCompEqIdx] += fluxVars.KmvpNormal(phaseIdx) - * (massUpwindWeight_ - * up.molarDensity(phaseIdx) - * up.mobility(phaseIdx) - + - (1.0 - massUpwindWeight_) - * dn.molarDensity(phaseIdx) - * dn.mobility(phaseIdx)); - - - Valgrind::CheckDefined(fluxVars.KmvpNormal(phaseIdx)); - Valgrind::CheckDefined(up.molarDensity(phaseIdx)); - Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); - } - } - } - } - - /*! - * \brief Evaluates the diffusive mass flux of all components over - * a face of a sub-control volume. - * - * \param flux The 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 - { - //Loop calculates the diffusive flux for every component in a phase. The amount of moles of a component - //(eg Air in liquid) in a phase - //which is not the main component (eg. H2O in the liquid phase) moved from i to j equals the amount of moles moved - //from the main component in a phase (eg. H2O in the liquid phase) from j to i. So two fluxes in each component loop - // are calculated in the same phase. - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - //add diffusive fluxes only to the component balances - if (replaceCompEqIdx != (conti0EqIdx + compIdx)) - { - Scalar diffCont = - fluxVars.porousDiffCoeff(phaseIdx ,compIdx) - * fluxVars.molarDensity(phaseIdx) - * (fluxVars.moleFractionGrad(phaseIdx, compIdx) - * fluxVars.face().normal); - flux[conti0EqIdx + compIdx] += diffCont; - flux[conti0EqIdx + phaseIdx] -= diffCont; - } - } - } - -protected: - - void evalPhaseStorage_(int phaseIdx) - { - // evaluate the storage terms of a single phase - for (int i=0; i < this->fvGeometry_().numScv; i++) - { - PrimaryVariables &result = this->residual_[i]; - const ElementVolumeVariables &elemVolVars = this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[i]; - - // compute storage term of all fluid components within all phases - result = 0; - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - result[conti0EqIdx + compIdx] += volVars.density(phaseIdx) - * volVars.saturation(phaseIdx) - * volVars.massFraction(phaseIdx, compIdx) - * volVars.porosity(); - } - result *= this->fvGeometry_().subContVol[i].volume; - } - } - - Implementation *asImp_() - { return static_cast<Implementation *> (this); } - const Implementation *asImp_() const - { return static_cast<const Implementation *> (this); } - -public: - Scalar massUpwindWeight_; -}; - -} // end namespace +#include <dumux/porousmediumflow/2pnc/implicit/localresidual.hh> #endif diff --git a/dumux/implicit/2pnc/2pncmodel.hh b/dumux/implicit/2pnc/2pncmodel.hh index 11201d35d5..a42f648246 100644 --- a/dumux/implicit/2pnc/2pncmodel.hh +++ b/dumux/implicit/2pnc/2pncmodel.hh @@ -1,741 +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 Adaption of the fully implicit box scheme to the two-phase n-component flow model. -*/ +#ifndef DUMUX_2PNC_MODEL_HH_OLD +#define DUMUX_2PNC_MODEL_HH_OLD -#ifndef DUMUX_2PNC_MODEL_HH -#define DUMUX_2PNC_MODEL_HH +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/model.hh instead -#include <dumux/porousmediumflow/implicit/velocityoutput.hh> - -#include "2pncproperties.hh" -#include "2pncindices.hh" -#include "2pnclocalresidual.hh" - -namespace Dumux -{ -/*! - * \ingroup TwoPNCModel - * \brief Adaption of the fully implicit scheme to the - * two-phase n-component fully implicit model. - * - * This model implements two-phase n-component flow of two compressible and - * partially miscible fluids \f$\alpha \in \{ w, n \}\f$ composed of the n components - * \f$\kappa \in \{ w, a,\cdots \}\f$. The standard multiphase Darcy - * approach is used as the equation for the conservation of momentum: - * \f[ - v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} - \left(\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) - * \f] - * - * By inserting this into the equations for the conservation of the - * components, one gets one transport equation for each component - * \f{eqnarray} - && \phi \frac{\partial (\sum_\alpha \varrho_\alpha X_\alpha^\kappa S_\alpha )} - {\partial t} - - \sum_\alpha \text{div} \left\{ \varrho_\alpha X_\alpha^\kappa - \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} - (\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g}) \right\} - \nonumber \\ \nonumber \\ - &-& \sum_\alpha \text{div} \left\{{\bf D_{\alpha, pm}^\kappa} \varrho_{\alpha} \text{grad}\, X^\kappa_{\alpha} \right\} - - \sum_\alpha q_\alpha^\kappa = 0 \qquad \kappa \in \{w, a,\cdots \} \, , - \alpha \in \{w, g\} - \f} - * - * All equations are discretized using a vertex-centered finite volume (box) - * or cell-centered finite volume scheme (this is not done for 2pnc approach yet, however possible) as - * spatial and the implicit Euler method as time discretization. - * - * By using constitutive relations for the capillary pressure \f$p_c = - * p_n - p_w\f$ and relative permeability \f$k_{r\alpha}\f$ and taking - * advantage of the fact that \f$S_w + S_n = 1\f$ and \f$X^\kappa_w + X^\kappa_n = 1\f$, the number of - * unknowns can be reduced to number of components. - * - * The used primary variables are, like in the two-phase model, either \f$p_w\f$ and \f$S_n\f$ - * or \f$p_n\f$ and \f$S_w\f$. The formulation which ought to be used can be - * specified by setting the <tt>Formulation</tt> property to either - * TwoPTwoCIndices::pWsN or TwoPTwoCIndices::pNsW. By - * default, the model uses \f$p_w\f$ and \f$S_n\f$. - * - * Moreover, the second primary variable depends on the phase state, since a - * primary variable switch is included. The phase state is stored for all nodes - * of the system. The model is uses mole fractions. - *Following cases can be distinguished: - * <ul> - * <li> Both phases are present: The saturation is used (either \f$S_n\f$ or \f$S_w\f$, dependent on the chosen <tt>Formulation</tt>), - * as long as \f$ 0 < S_\alpha < 1\f$</li>. - * <li> Only wetting phase is present: The mass fraction of, e.g., air in the wetting phase \f$X^a_w\f$ is used, - * as long as the maximum mass fraction is not exceeded (\f$X^a_w<X^a_{w,max}\f$)</li> - * <li> Only non-wetting phase is present: The mass fraction of, e.g., water in the non-wetting phase, \f$X^w_n\f$, is used, - * as long as the maximum mass fraction is not exceeded (\f$X^w_n<X^w_{n,max}\f$)</li> - * </ul> - */ - -template<class TypeTag> -class TwoPNCModel: public GET_PROP_TYPE(TypeTag, BaseModel) -{ - typedef typename GET_PROP_TYPE(TypeTag, BaseModel) ParentType; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum { dim = GridView::dimension }; - enum { dimWorld = GridView::dimensionworld }; - - enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; - enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; - enum { numComponents = GET_PROP_VALUE(TypeTag, NumComponents) }; - enum { numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents) }; - - enum { - pressureIdx = Indices::pressureIdx, - switchIdx = Indices::switchIdx - }; - enum { - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx - }; - enum { - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx - }; - enum { - wPhaseOnly = Indices::wPhaseOnly, - nPhaseOnly = Indices::nPhaseOnly, - bothPhases = Indices::bothPhases - }; - enum { - plSg = TwoPNCFormulation::plSg, - pgSl = TwoPNCFormulation::pgSl, - formulation = GET_PROP_VALUE(TypeTag, Formulation) - }; - - typedef CompositionalFluidState<Scalar, FluidSystem> FluidState; - - typedef typename GridView::template Codim<dim>::Entity Vertex; - typedef typename GridView::template Codim<0>::Entity Element; - - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - typedef typename GridView::ctype CoordScalar; - typedef Dune::FieldMatrix<CoordScalar, dimWorld, dimWorld> Tensor; - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - -public: - /*! - * \brief Initialize the static data with the initial solution. - * - * \param problem The problem to be solved - */ - void init(Problem &problem) - { - ParentType::init(problem); - - unsigned numDofs = this->numDofs(); - - staticDat_.resize(numDofs); - - setSwitched_(false); - - for (const auto& element : Dune::elements(this->gridView_())) - { - if (!isBox) // i.e. cell-centered discretization - { - int dofIdxGlobal = this->dofMapper().index(element); - const GlobalPosition &globalPos = element.geometry().center(); - - // initialize phase presence - staticDat_[dofIdxGlobal].phasePresence - = this->problem_().initialPhasePresence(*(this->gridView_().template begin<dim>()), - dofIdxGlobal, globalPos); - staticDat_[dofIdxGlobal].wasSwitched = false; - - staticDat_[dofIdxGlobal].oldPhasePresence - = staticDat_[dofIdxGlobal].phasePresence; - } - } - - if (isBox) // i.e. vertex-centered discretization - { - for (const auto& vertex : Dune::vertices(this->gridView_())) - { - int dofIdxGlobal = this->dofMapper().index(vertex); - const GlobalPosition &globalPos = vertex.geometry().corner(0); - - // initialize phase presence - staticDat_[dofIdxGlobal].phasePresence - = this->problem_().initialPhasePresence(vertex, dofIdxGlobal, - globalPos); - staticDat_[dofIdxGlobal].wasSwitched = false; - - staticDat_[dofIdxGlobal].oldPhasePresence - = staticDat_[dofIdxGlobal].phasePresence; - } - } - } - - /*! - * \brief Compute the total storage of all conservation quantities in one phase - * - * \param storage Contains the storage of each component in one phase - * \param phaseIdx The phase index - */ - void globalPhaseStorage(PrimaryVariables &storage, int phaseIdx) - { - storage = 0; - - for (const auto& element : Dune::elements(this->gridView_())) - { - if(element.partitionType() == Dune::InteriorEntity) - { - this->localResidual().evalPhaseStorage(element, phaseIdx); - - for (unsigned int i = 0; i < this->localResidual().storageTerm().size(); ++i) - storage += this->localResidual().storageTerm()[i]; - } - } - - this->gridView_().comm().sum(storage); - } - - /*! - * \brief Called by the update() method if applying the newton - * method was unsuccessful. - */ - void updateFailed() - { - ParentType::updateFailed(); - - setSwitched_(false); - resetPhasePresence_(); - } - - /*! - * \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() - { - ParentType::advanceTimeLevel(); - - // update the phase state - updateOldPhasePresence_(); - setSwitched_(false); - } - - /*! - * \brief Return true if the primary variables were switched for - * at least one vertex after the last timestep. - */ - bool switched() const - { - return switchFlag_; - } - - /*! - * \brief Returns the phase presence of the current or the old solution of a vertex. - * - * \param globalVertexIdx The global vertex index - * \param oldSol Evaluate function with solution of current or previous time step - */ - int phasePresence(int globalVertexIdx, bool oldSol) const - { - return oldSol ? staticDat_[globalVertexIdx].oldPhasePresence - : staticDat_[globalVertexIdx].phasePresence; - } - - /*! - * \brief Append all quantities of interest which can be derived - * from the solution of the current time step to the VTK - * writer. - * - * \param sol The solution vector - * \param writer The writer for multi-file VTK datasets - */ - 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; - - // get the number of degrees of freedom - unsigned numDofs = this->numDofs(); - - ScalarField *Sg = writer.allocateManagedBuffer (numDofs); - ScalarField *Sl = writer.allocateManagedBuffer (numDofs); - ScalarField *pg = writer.allocateManagedBuffer (numDofs); - ScalarField *pl = writer.allocateManagedBuffer (numDofs); - ScalarField *pc = writer.allocateManagedBuffer (numDofs); - ScalarField *rhoL = writer.allocateManagedBuffer (numDofs); - ScalarField *rhoG = writer.allocateManagedBuffer (numDofs); - ScalarField *mobL = writer.allocateManagedBuffer (numDofs); - ScalarField *mobG = writer.allocateManagedBuffer (numDofs); - ScalarField *temperature = writer.allocateManagedBuffer (numDofs); - ScalarField *poro = writer.allocateManagedBuffer (numDofs); - ScalarField *boxVolume = writer.allocateManagedBuffer (numDofs); - VectorField *velocityN = writer.template allocateManagedBuffer<double, dim>(numDofs); - VectorField *velocityW = writer.template allocateManagedBuffer<double, dim>(numDofs); - ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - // initialize velocity fields - for (unsigned int i = 0; i < numDofs; ++i) - { - (*velocityN)[i] = Scalar(0); - (*velocityW)[i] = Scalar(0); - } - } - - ScalarField *moleFraction[numPhases][numComponents]; - for (int i = 0; i < numPhases; ++i) - for (int j = 0; j < numComponents; ++j) - moleFraction[i][j] = writer.allocateManagedBuffer(numDofs); - - ScalarField *molarity[numComponents]; - for (int j = 0; j < numComponents ; ++j) - molarity[j] = writer.allocateManagedBuffer(numDofs); - - ScalarField *Perm[dim]; - for (int j = 0; j < dim; ++j) //Permeability only in main directions xx and yy - Perm[j] = writer.allocateManagedBuffer(numDofs); - - *boxVolume = 0; - - unsigned numElements = this->gridView_().size(0); - ScalarField *rank = writer.allocateManagedBuffer (numElements); - - FVElementGeometry fvGeometry; - VolumeVariables volVars; - ElementVolumeVariables elemVolVars; - - for (const auto& element : Dune::elements(this->gridView_())) - { - int eIdxGlobal = this->problem_().elementMapper().index(element); - (*rank)[eIdxGlobal] = this->gridView_().comm().rank(); - fvGeometry.update(this->gridView_(), element); - - elemVolVars.update(this->problem_(), - element, - fvGeometry, - false /* oldSol? */); - - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); - - volVars.update(sol[dofIdxGlobal], - this->problem_(), - element, - fvGeometry, - scvIdx, - false); - - GlobalPosition globalPos = fvGeometry.subContVol[scvIdx].global; - (*Sg)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx); - (*Sl)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx); - (*pg)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx); - (*pl)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx); - (*pc)[dofIdxGlobal] = elemVolVars[scvIdx].capillaryPressure(); - (*rhoL)[dofIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx); - (*rhoG)[dofIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx); - (*mobL)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(wPhaseIdx); - (*mobG)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(nPhaseIdx); - (*boxVolume)[dofIdxGlobal] += fvGeometry.subContVol[scvIdx].volume; - (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity(); - (*temperature)[dofIdxGlobal] = elemVolVars[scvIdx].temperature(); - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - (*moleFraction[phaseIdx][compIdx])[dofIdxGlobal]= volVars.moleFraction(phaseIdx,compIdx); - Valgrind::CheckDefined((*moleFraction[phaseIdx][compIdx])[dofIdxGlobal]); - } - } - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - (*molarity[compIdx])[dofIdxGlobal] = (volVars.molarity(wPhaseIdx, compIdx)); - - Tensor K = perm_(this->problem_().spatialParams().intrinsicPermeability(element, fvGeometry, scvIdx)); - - for (int j = 0; j<dim; ++j) - (*Perm[j])[dofIdxGlobal] = K[j][j] /* volVars.permFactor()*/; - }; - - // velocity output - if(velocityOutput.enableOutput()){ - velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); - velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); - } - - } // loop over element - - writer.attachDofData(*Sg, "Sg", isBox); - writer.attachDofData(*Sl, "Sl", isBox); - writer.attachDofData(*pg, "pg", isBox); - writer.attachDofData(*pl, "pl", isBox); - writer.attachDofData(*pc, "pc", isBox); - writer.attachDofData(*rhoL, "rhoL", isBox); - writer.attachDofData(*rhoG, "rhoG", isBox); - writer.attachDofData(*mobL, "mobL", isBox); - writer.attachDofData(*mobG, "mobG", isBox); - writer.attachDofData(*poro, "porosity", isBox); - writer.attachDofData(*temperature, "temperature", isBox); - writer.attachDofData(*boxVolume, "boxVolume", isBox); - writer.attachDofData(*Perm[0], "Kxx", isBox); - if (dim >= 2) - writer.attachDofData(*Perm[1], "Kyy", isBox); - if (dim == 3) - writer.attachDofData(*Perm[2], "Kzz", isBox); - - for (int i = 0; i < numPhases; ++i) - { - for (int j = 0; j < numComponents; ++j) - { - std::ostringstream oss; - oss << "x" - << FluidSystem::componentName(j) - << FluidSystem::phaseName(i); - writer.attachDofData(*moleFraction[i][j], oss.str().c_str(), isBox); - } - } - - for (int j = 0; j < numComponents; ++j) - { - std::ostringstream oss; - oss << "m^w_" - << FluidSystem::componentName(j); - writer.attachDofData(*molarity[j], oss.str().c_str(), isBox); - } - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - writer.attachDofData(*velocityW, "velocityW", isBox, dim); - writer.attachDofData(*velocityN, "velocityN", isBox, dim); - } - - writer.attachCellData(*rank, "process rank"); - } - - /*! - * \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 - */ - template<class Entity> - void serializeEntity(std::ostream &outStream, const Entity &entity) - { - // write primary variables - ParentType::serializeEntity(outStream, entity); - int dofIdxGlobal = this->dofMapper().index(entity); - - if (!outStream.good()) - DUNE_THROW(Dune::IOError, "Could not serialize vertex " << dofIdxGlobal); - - outStream << staticDat_[dofIdxGlobal].phasePresence << " "; - } - - /*! - * \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 - */ - template<class Entity> - void deserializeEntity(std::istream &inStream, const Entity &entity) - { - // read primary variables - ParentType::deserializeEntity(inStream, entity); - int dofIdxGlobal = this->dofMapper().index(entity); - - if (!inStream.good()) - DUNE_THROW(Dune::IOError, - "Could not deserialize vertex " << dofIdxGlobal); - - inStream >> staticDat_[dofIdxGlobal].phasePresence; - staticDat_[dofIdxGlobal].oldPhasePresence - = staticDat_[dofIdxGlobal].phasePresence; - - } - - /*! - * \brief Update the static data of all vertices in the grid. - * - * \param curGlobalSol The current global solution - * \param oldGlobalSol The previous global solution - */ - void updateStaticData(SolutionVector &curGlobalSol, - const SolutionVector &oldGlobalSol) - { - bool wasSwitched = false; - - for (unsigned i = 0; i < staticDat_.size(); ++i) - staticDat_[i].visited = false; - - FVElementGeometry fvGeometry; - static VolumeVariables volVars; - for (const auto& element : Dune::elements(this->gridView_())) - { - fvGeometry.update(this->gridView_(), element); - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); - - if (staticDat_[dofIdxGlobal].visited) - continue; - - staticDat_[dofIdxGlobal].visited = true; - volVars.update(curGlobalSol[dofIdxGlobal], - this->problem_(), - element, - fvGeometry, - scvIdx, - false); - const GlobalPosition &global = element.geometry().corner(scvIdx); - if (primaryVarSwitch_(curGlobalSol, volVars, dofIdxGlobal, global)) - wasSwitched = true; - } - } - - // make sure that if there was a variable switch in an - // other partition we will also set the switch flag - // for our partition. - wasSwitched = this->gridView_().comm().max(wasSwitched); - - setSwitched_(wasSwitched); - } - -protected: - /*! - * \brief Data which is attached to each vertex and is not only - * stored locally. - */ - struct StaticVars - { - int phasePresence; - bool wasSwitched; - - int oldPhasePresence; - bool visited; - }; - - Tensor perm_(Scalar perm) - { - Tensor K(0.0); - - for(int i=0; i<dim; i++) - K[i][i] = perm; - - return K; - } - - Tensor perm_(Tensor perm) - { - return perm; - } - - /*! - * \brief Reset the current phase presence of all vertices to the old one. - * - * This is done after an update failed. - */ - void resetPhasePresence_() - { - int numDofs = this->gridView_().size(dim); - for (int i = 0; i < numDofs; ++i) - { - staticDat_[i].phasePresence - = staticDat_[i].oldPhasePresence; - staticDat_[i].wasSwitched = false; - } - } - - /*! - * \brief Set the old phase of all verts state to the current one. - */ - void updateOldPhasePresence_() - { - int numDofs = this->gridView_().size(dim); - for (int i = 0; i < numDofs; ++i) - { - staticDat_[i].oldPhasePresence - = staticDat_[i].phasePresence; - staticDat_[i].wasSwitched = false; - } - } - - /*! - * \brief Set whether there was a primary variable switch after in - * the last timestep. - */ - void setSwitched_(bool yesno) - { - switchFlag_ = yesno; - } - - // perform variable switch at a vertex; Returns true if a - // variable switch was performed. - bool primaryVarSwitch_(SolutionVector &globalSol, - const VolumeVariables &volVars, int dofIdxGlobal, - const GlobalPosition &globalPos) - { - - // evaluate primary variable switch - bool wouldSwitch = false; - int phasePresence = staticDat_[dofIdxGlobal].phasePresence; - int newPhasePresence = phasePresence; - - //check if a primary variable switch is necessary - if (phasePresence == bothPhases) - { - Scalar Smin = 0; //saturation threshold - if (staticDat_[dofIdxGlobal].wasSwitched) - Smin = -0.01; - - //if saturation of liquid phase is smaller 0 switch - if (volVars.saturation(wPhaseIdx) <= Smin) - { - wouldSwitch = true; - //liquid phase has to disappear - std::cout << "Liquid Phase disappears at vertex " << dofIdxGlobal - << ", coordinated: " << globalPos << ", Sl: " - << volVars.saturation(wPhaseIdx) << std::endl; - newPhasePresence = nPhaseOnly; - - //switch not depending on formulation - //switch "Sl" to "xgH20" - globalSol[dofIdxGlobal][switchIdx] - = volVars.moleFraction(nPhaseIdx, wCompIdx /*H2O*/); - - //switch all secondary components to mole fraction in gas phase - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - globalSol[dofIdxGlobal][compIdx] = volVars.moleFraction(nPhaseIdx,compIdx); - } - //if saturation of gas phase is smaller than 0 switch - else if (volVars.saturation(nPhaseIdx) <= Smin) - { - wouldSwitch = true; - //gas phase has to disappear - std::cout << "Gas Phase disappears at vertex " << dofIdxGlobal - << ", coordinated: " << globalPos << ", Sg: " - << volVars.saturation(nPhaseIdx) << std::endl; - newPhasePresence = wPhaseOnly; - - //switch "Sl" to "xlN2" - globalSol[dofIdxGlobal][switchIdx] - = volVars.moleFraction(wPhaseIdx, nCompIdx /*N2*/); - } - } - else if (phasePresence == nPhaseOnly) - { - Scalar xlmax = 1; - Scalar sumxl = 0; - //Calculate sum of mole fractions in the hypothetical liquid phase - for (int compIdx = 0; compIdx < numComponents; compIdx++) - { - sumxl += volVars.moleFraction(wPhaseIdx, compIdx); - } - if (sumxl > xlmax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xlmax *=1.02; - //liquid phase appears if sum is larger than one - if (sumxl/*sum of mole fractions*/ > xlmax/*1*/) - { - std::cout << "Liquid Phase appears at vertex " << dofIdxGlobal - << ", coordinated: " << globalPos << ", sumxl: " - << sumxl << std::endl; - newPhasePresence = bothPhases; - - //saturation of the liquid phase set to 0.0001 (if formulation pgSl and vice versa) - if (formulation == pgSl) - globalSol[dofIdxGlobal][switchIdx] = 0.0001; - else if (formulation == plSg) - globalSol[dofIdxGlobal][switchIdx] = 0.9999; - - //switch all secondary components back to liquid mole fraction - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - globalSol[dofIdxGlobal][compIdx] = volVars.moleFraction(wPhaseIdx,compIdx); - } - } - else if (phasePresence == wPhaseOnly) - { - Scalar xgmax = 1; - Scalar sumxg = 0; - //Calculate sum of mole fractions in the hypothetical liquid phase - for (int compIdx = 0; compIdx < numComponents; compIdx++) - { - sumxg += volVars.moleFraction(nPhaseIdx, compIdx); - } - if (sumxg > xgmax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xgmax *=1.02; - //liquid phase appears if sum is larger than one - if (sumxg > xgmax) - { - std::cout << "Gas Phase appears at vertex " << dofIdxGlobal - << ", coordinated: " << globalPos << ", sumxg: " - << sumxg << std::endl; - newPhasePresence = bothPhases; - //saturation of the liquid phase set to 0.9999 (if formulation pgSl and vice versa) - if (formulation == pgSl) - globalSol[dofIdxGlobal][switchIdx] = 0.9999; - else if (formulation == plSg) - globalSol[dofIdxGlobal][switchIdx] = 0.0001; - - } - } - - - staticDat_[dofIdxGlobal].phasePresence = newPhasePresence; - staticDat_[dofIdxGlobal].wasSwitched = wouldSwitch; - return phasePresence != newPhasePresence; - } - - // parameters given in constructor - std::vector<StaticVars> staticDat_; - bool switchFlag_; -}; - -} - -#include "2pncpropertydefaults.hh" +#include <dumux/porousmediumflow/2pnc/implicit/model.hh> #endif diff --git a/dumux/implicit/2pnc/2pncnewtoncontroller.hh b/dumux/implicit/2pnc/2pncnewtoncontroller.hh index 2f970c83b1..d50d55380e 100644 --- a/dumux/implicit/2pnc/2pncnewtoncontroller.hh +++ b/dumux/implicit/2pnc/2pncnewtoncontroller.hh @@ -1,105 +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 A two-phase n-component specific controller for the newton solver. - */ -#ifndef DUMUX_2PNC_NEWTON_CONTROLLER_HH -#define DUMUX_2PNC_NEWTON_CONTROLLER_HH +#ifndef DUMUX_2PNC_NEWTON_CONTROLLER_HH_OLD +#define DUMUX_2PNC_NEWTON_CONTROLLER_HH_OLD -#include "2pncproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/newtoncontroller.hh instead -#include <dumux/nonlinear/newtoncontroller.hh> - -namespace Dumux { -/*! - * \ingroup Newton - * \ingroup TwoPNCModel - * \brief A two-phase n-component 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. - */ -template <class TypeTag> -class TwoPNCNewtonController : public NewtonController<TypeTag> -{ - typedef NewtonController<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(Problem)) Problem; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(SolutionVector)) SolutionVector; - -public: - TwoPNCNewtonController(Problem &problem) - : ParentType(problem) - {}; - - - /*! - * \brief - * Suggest a new time step size based either on the number of newton - * iterations required or on the variable switch - * - * \param uCurrentIter The current global solution vector - * \param uLastIter The previous global solution vector - * - */ - void newtonEndStep(SolutionVector &uCurrentIter, - const SolutionVector &uLastIter) - { - int succeeded; - try { - // call the method of the base class - this->method().model().updateStaticData(uCurrentIter, uLastIter); - ParentType::newtonEndStep(uCurrentIter, uLastIter); - - succeeded = 1; - if (this->gridView_().comm().size() > 1) - succeeded = this->gridView_().comm().min(succeeded); - } - catch (Dumux::NumericalProblem &e) - { - std::cout << "rank " << this->problem_().gridView().comm().rank() - << " caught an exception while updating:" << e.what() - << "\n"; - succeeded = 0; - if (this->gridView_().comm().size() > 1) - succeeded = this->gridView_().comm().min(succeeded); - } - - if (!succeeded) { - DUNE_THROW(NumericalProblem, - "A process did not succeed in linearizing the system"); - } - } - - /*! - * \brief Returns true if the current solution can be considered to - * be accurate enough - */ - bool newtonConverged() - { - if (this->method().model().switched()) - return false; - - return ParentType::newtonConverged(); - } -}; -} +#include <dumux/porousmediumflow/2pnc/implicit/newtoncontroller.hh> #endif diff --git a/dumux/implicit/2pnc/2pncproperties.hh b/dumux/implicit/2pnc/2pncproperties.hh index 44e495060a..1ecb36db30 100644 --- a/dumux/implicit/2pnc/2pncproperties.hh +++ b/dumux/implicit/2pnc/2pncproperties.hh @@ -1,82 +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 TwoPNCModel - * - * \file - * - * \brief Defines the properties required for the two-phase n-component - * fully implicit model. - */ -#ifndef DUMUX_2PNC_PROPERTIES_HH -#define DUMUX_2PNC_PROPERTIES_HH +#ifndef DUMUX_2PNC_PROPERTIES_HH_OLD +#define DUMUX_2PNC_PROPERTIES_HH_OLD -#include <dumux/implicit/box/properties.hh> -#include <dumux/implicit/cellcentered/properties.hh> -#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/properties.hh instead -namespace Dumux -{ - -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tag for the implicit isothermal two phase n component problems -NEW_TYPE_TAG(TwoPNC); -NEW_TYPE_TAG(BoxTwoPNC, INHERITS_FROM(BoxModel, TwoPNC)); -NEW_TYPE_TAG(CCTwoPNC, INHERITS_FROM(CCModel, TwoPNC)); - -//! The type tag for the implicit non-isothermal two phase n component problems -NEW_TYPE_TAG(TwoPNCNI, INHERITS_FROM(TwoPNC, NonIsothermal)); -NEW_TYPE_TAG(BoxTwoPNCNI, INHERITS_FROM(BoxModel, TwoPNCNI)); -NEW_TYPE_TAG(CCTwoPNCNI, INHERITS_FROM(CCModel, TwoPNCNI)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// - -NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system -NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system -NEW_PROP_TAG(NumMajorComponents); //!< Number of major fluid components which are considered in the calculation of the phase density -NEW_PROP_TAG(TwoPNCIndices); //!< Enumerations for the 2pncMin models -NEW_PROP_TAG(Formulation); //!< The formulation of the model -NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters -NEW_PROP_TAG(FluidSystem); //!< Type of the multi-component relations -NEW_PROP_TAG(FluidState); //!< Type of the fluid state of the 2pnc model -NEW_PROP_TAG(Indices); //!< Enumerations for the model -NEW_PROP_TAG(Chemistry); //!< The chemistry class with which solves equlibrium reactions - -NEW_PROP_TAG(MaterialLaw); //!< The material law which ought to be used (extracted from the spatial parameters) -NEW_PROP_TAG(MaterialLawParams); //!< The parameters of the material law (extracted from the spatial parameters) - -NEW_PROP_TAG(ReplaceCompEqIdx); //!< The index of the total mass balance equation, if one component balance is replaced (ReplaceCompEqIdx < NumComponents) -NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output -NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem -NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The value of the upwind weight for the mass conservation equations -NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< The value of the upwind parameter for the mobility -NEW_PROP_TAG(BaseFluxVariables); //! The base flux variables -} -} +#include <dumux/porousmediumflow/2pnc/implicit/properties.hh> #endif diff --git a/dumux/implicit/2pnc/2pncpropertydefaults.hh b/dumux/implicit/2pnc/2pncpropertydefaults.hh index 4d78e5f1c0..e60b1422fb 100644 --- a/dumux/implicit/2pnc/2pncpropertydefaults.hh +++ b/dumux/implicit/2pnc/2pncpropertydefaults.hh @@ -1,226 +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 TwoPNCModel - * \file - * - * \brief Defines default values for most properties required by the - * two-phase n-component fully implicit model. - */ -#ifndef DUMUX_2PNC_PROPERTY_DEFAULTS_HH -#define DUMUX_2PNC_PROPERTY_DEFAULTS_HH +#ifndef DUMUX_2PNC_PROPERTY_DEFAULTS_HH_OLD +#define DUMUX_2PNC_PROPERTY_DEFAULTS_HH_OLD -#include "2pncindices.hh" -#include "2pncmodel.hh" -#include "2pncindices.hh" -#include "2pncfluxvariables.hh" -#include "2pncvolumevariables.hh" -#include "2pncproperties.hh" -#include "2pncnewtoncontroller.hh" +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/propertydefaults.hh instead -#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> -#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> -#include <dumux/material/spatialparams/implicitspatialparams.hh> -#include <dumux/material/fluidmatrixinteractions/2p/thermalconductivitysomerton.hh> - -namespace Dumux -{ - -namespace Properties { -////////////////////////////////////////////////////////////////// -// Property values -////////////////////////////////////////////////////////////////// - -/*! - * \brief Set the property for the number of components. - * - * We just forward the number from the fluid system - * - */ -SET_PROP(TwoPNC, NumComponents) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numComponents; - -}; -//! Set as default that no component mass balance is replaced by the total mass balance -SET_PROP(TwoPNC, ReplaceCompEqIdx) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numComponents; -}; -//! The major components belonging to the existing phases are mentioned here e.g., 2 for water and air being the major component in the liquid and gas phases in a 2 phase system -SET_PROP(TwoPNC, NumMajorComponents) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numPhases; - static_assert(value == 2, - "The model is restricted to two-phases, thus number of major components must also be two."); -}; - -/*! - * \brief Set the property for the number of fluid phases. - * - * We just forward the number from the fluid system and use an static - * assert to make sure it is 2. - */ -SET_PROP(TwoPNC, NumPhases) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numPhases; - static_assert(value == 2, - "Only fluid systems with 2 fluid phases are supported by the 2p-nc model!"); -}; -/*! - * \brief Set the property for the number of equations: For each existing component one equation has to be solved. - */ -SET_PROP(TwoPNC, NumEq) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numComponents; -}; - -/*! - * \brief The fluid state which is used by the volume variables to - * store the thermodynamic state. This should be chosen - * appropriately for the model ((non-)isothermal, equilibrium, ...). - * This can be done in the problem. - */ -SET_PROP(TwoPNC, 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 the default formulation to pl-Sg: This can be over written in the problem. -SET_INT_PROP(TwoPNC, Formulation, TwoPNCFormulation::plSg); - -//! Set the property for the material parameters by extracting it from the material law. -SET_PROP(TwoPNC, MaterialLawParams) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(MaterialLaw)) MaterialLaw; - -public: - typedef typename MaterialLaw::Params type; -}; - -//! Use the 2pnc local residual -SET_TYPE_PROP(TwoPNC, LocalResidual, TwoPNCLocalResidual<TypeTag>); - -//! Use the 2pnc newton controller -SET_TYPE_PROP(TwoPNC, NewtonController, TwoPNCNewtonController<TypeTag>); - -//! the Model property -SET_TYPE_PROP(TwoPNC, Model, TwoPNCModel<TypeTag>); - -//! the VolumeVariables property -SET_TYPE_PROP(TwoPNC, VolumeVariables, TwoPNCVolumeVariables<TypeTag>); - -//! the FluxVariables property -SET_TYPE_PROP(TwoPNC, FluxVariables, TwoPNCFluxVariables<TypeTag>); - -//! define the base flux variables to realize Darcy flow -SET_TYPE_PROP(TwoPNC, BaseFluxVariables, ImplicitDarcyFluxVariables<TypeTag>); - -//! the upwind weight for the mass conservation equations. -SET_SCALAR_PROP(TwoPNC, ImplicitMassUpwindWeight, 1.0); - -//! Set default mobility upwind weight to 1.0, i.e. fully upwind -SET_SCALAR_PROP(TwoPNC, ImplicitMobilityUpwindWeight, 1.0); - -//! The indices required by the isothermal 2pnc model -SET_TYPE_PROP(TwoPNC, Indices, TwoPNCIndices <TypeTag, /*PVOffset=*/0>); - -//! Use the ImplicitSpatialParams by default -SET_TYPE_PROP(TwoPNC, SpatialParams, ImplicitSpatialParams<TypeTag>); - -//! Enable gravity by default -SET_BOOL_PROP(TwoPNC, ProblemEnableGravity, true); - -//! Disable velocity output by default -SET_BOOL_PROP(TwoPNC, VtkAddVelocity, false); - -//! Somerton is used as default model to compute the effective thermal heat conductivity -SET_PROP(TwoPNCNI, ThermalConductivityModel) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; -public: - typedef ThermalConductivitySomerton<Scalar, Indices> type; -}; - -//! temperature is already written by the isothermal model -SET_BOOL_PROP(TwoPNCNI, NiOutputLevel, 0); - -////////////////////////////////////////////////////////////////// -// Property values for isothermal model required for the general non-isothermal model -////////////////////////////////////////////////////////////////// - -// set isothermal Model -SET_TYPE_PROP(TwoPNCNI, IsothermalModel, TwoPNCModel<TypeTag>); - -// set isothermal FluxVariables -SET_TYPE_PROP(TwoPNCNI, IsothermalFluxVariables, TwoPNCFluxVariables<TypeTag>); - -//set isothermal VolumeVariables -SET_TYPE_PROP(TwoPNCNI, IsothermalVolumeVariables, TwoPNCVolumeVariables<TypeTag>); - -//set isothermal LocalResidual -SET_TYPE_PROP(TwoPNCNI, IsothermalLocalResidual, TwoPNCLocalResidual<TypeTag>); - -//set isothermal Indices -SET_TYPE_PROP(TwoPNCNI, IsothermalIndices, TwoPNCIndices<TypeTag, /*PVOffset=*/0>); - -//set isothermal NumEq -SET_PROP(TwoPNCNI, IsothermalNumEq) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numComponents; -}; - - -} - -} +#include <dumux/porousmediumflow/2pnc/implicit/propertydefaults.hh> #endif diff --git a/dumux/implicit/2pnc/2pncvolumevariables.hh b/dumux/implicit/2pnc/2pncvolumevariables.hh index 2e515ba8c4..22f705ef64 100644 --- a/dumux/implicit/2pnc/2pncvolumevariables.hh +++ b/dumux/implicit/2pnc/2pncvolumevariables.hh @@ -1,529 +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 Contains the quantities which are constant within a - * finite volume in the two-phase, n-component model. - */ -#ifndef DUMUX_2PNC_VOLUME_VARIABLES_HH -#define DUMUX_2PNC_VOLUME_VARIABLES_HH +#ifndef DUMUX_2PNC_VOLUME_VARIABLES_HH_OLD +#define DUMUX_2PNC_VOLUME_VARIABLES_HH_OLD -#include <iostream> -#include <vector> +#warning this header is deprecated, use dumux/porousmediumflow/2pnc/implicit/volumevariables.hh instead -#include <dumux/implicit/model.hh> -#include <dumux/material/fluidstates/compositionalfluidstate.hh> -#include <dumux/common/math.hh> - -#include "2pncproperties.hh" -#include "2pncindices.hh" -#include <dumux/material/constraintsolvers/computefromreferencephase2pnc.hh> -#include <dumux/material/constraintsolvers/miscible2pnccomposition.hh> - -namespace Dumux -{ - -/*! - * \ingroup TwoPNCModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are are constant within a - * finite volume in the two-phase, n-component model. - */ -template <class TypeTag> -class TwoPNCVolumeVariables : public ImplicitVolumeVariables<TypeTag> -{ - typedef ImplicitVolumeVariables<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum - { - dim = GridView::dimension, - dimWorld=GridView::dimensionworld, - - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents), - - // formulations - formulation = GET_PROP_VALUE(TypeTag, Formulation), - plSg = TwoPNCFormulation::plSg, - pgSl = TwoPNCFormulation::pgSl, - - // phase indices - wPhaseIdx = FluidSystem::wPhaseIdx, - nPhaseIdx = FluidSystem::nPhaseIdx, - - // component indices - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx, - - // phase presence enums - nPhaseOnly = Indices::nPhaseOnly, - wPhaseOnly = Indices::wPhaseOnly, - bothPhases = Indices::bothPhases, - - // primary variable indices - pressureIdx = Indices::pressureIdx, - switchIdx = Indices::switchIdx, - - }; - - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename Grid::ctype CoordScalar; - typedef Dumux::Miscible2pNCComposition<Scalar, FluidSystem> Miscible2pNCComposition; - typedef Dumux::ComputeFromReferencePhase2pNC<Scalar, FluidSystem> ComputeFromReferencePhase2pNC; - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; -public: - - typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; - - /*! - * \copydoc ImplicitVolumeVariables::update - * \param primaryVariables The primary Variables - */ - void update(const PrimaryVariables &primaryVariables, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int scvIdx, - bool isOldSol) - { - ParentType::update(primaryVariables, - problem, - element, - fvGeometry, - scvIdx, - isOldSol); - - completeFluidState(primaryVariables, problem, element, fvGeometry, scvIdx, fluidState_, isOldSol); - - ///////////// - // calculate the remaining quantities - ///////////// - const MaterialLawParams &materialParams = problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); - - // Second instance of a parameter cache. - // Could be avoided if diffusion coefficients also - // became part of the fluid state. - typename FluidSystem::ParameterCache paramCache; - paramCache.updateAll(fluidState_); - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - {// relative permeabilities - Scalar kr; - if (phaseIdx == wPhaseIdx) - kr = MaterialLaw::krw(materialParams, saturation(wPhaseIdx)); - else // ATTENTION: krn requires the liquid saturation - // as parameter! - kr = MaterialLaw::krn(materialParams, saturation(wPhaseIdx)); - mobility_[phaseIdx] = kr / fluidState_.viscosity(phaseIdx); - Valgrind::CheckDefined(mobility_[phaseIdx]); - int compIIdx = phaseIdx; - for(int compIdx = 0; compIdx < numComponents; ++compIdx) - { - int compJIdx = compIdx; - // binary diffusion coefficents - diffCoeff_[phaseIdx][compIdx] = 0.0; - if(compIIdx!= compJIdx) - diffCoeff_[phaseIdx][compIdx] = FluidSystem::binaryDiffusionCoefficient(fluidState_, - paramCache, - phaseIdx, - compIIdx, - compJIdx); - Valgrind::CheckDefined(diffCoeff_[phaseIdx][compIdx]); - } - } - - // porosity - porosity_ = problem.spatialParams().porosity(element, - fvGeometry, - scvIdx); - Valgrind::CheckDefined(porosity_); - // energy related quantities not contained in the fluid state - - asImp_().updateEnergy_(primaryVariables, problem,element, fvGeometry, scvIdx, isOldSol); - } - - /*! - * \copydoc ImplicitModel::completeFluidState - * \param isOldSol Specifies whether this is the previous solution or the current one - * \param primaryVariables The primary Variables - */ - static void completeFluidState(const PrimaryVariables& primaryVariables, - const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - int scvIdx, - FluidState& fluidState, - bool isOldSol = false) - - { - Scalar t = Implementation::temperature_(primaryVariables, problem, element, - fvGeometry, scvIdx); - fluidState.setTemperature(t); - - int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); - int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); - - ///////////// - // set the saturations - ///////////// - - Scalar Sg; - if (phasePresence == nPhaseOnly) - Sg = 1.0; - else if (phasePresence == wPhaseOnly) { - Sg = 0.0; - } - else if (phasePresence == bothPhases) { - if (formulation == plSg) - Sg = primaryVariables[switchIdx]; - else if (formulation == pgSl) - Sg = 1.0 - primaryVariables[switchIdx]; - else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); - } - else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); - fluidState.setSaturation(nPhaseIdx, Sg); - fluidState.setSaturation(wPhaseIdx, 1.0 - Sg); - - ///////////// - // set the pressures of the fluid phases - ///////////// - - // calculate capillary pressure - const MaterialLawParams &materialParams - = problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); - Scalar pc = MaterialLaw::pc(materialParams, 1 - Sg); - - // extract the pressures - if (formulation == plSg) { - fluidState.setPressure(wPhaseIdx, primaryVariables[pressureIdx]); - if (primaryVariables[pressureIdx] + pc < 0.0) - DUNE_THROW(Dumux::NumericalProblem,"Capillary pressure is too low"); - fluidState.setPressure(nPhaseIdx, primaryVariables[pressureIdx] + pc); - } - else if (formulation == pgSl) { - fluidState.setPressure(nPhaseIdx, primaryVariables[pressureIdx]); - // Here we check for (p_g - pc) in order to ensure that (p_l > 0) - if (primaryVariables[pressureIdx] - pc < 0.0) - { - std::cout<< "p_g: "<< primaryVariables[pressureIdx]<<" Cap_press: "<< pc << std::endl; - DUNE_THROW(Dumux::NumericalProblem,"Capillary pressure is too high"); - } - fluidState.setPressure(wPhaseIdx, primaryVariables[pressureIdx] - pc); - } - else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); - - ///////////// - // calculate the phase compositions - ///////////// - - typename FluidSystem::ParameterCache paramCache; - - // now comes the tricky part: calculate phase composition - if (phasePresence == bothPhases) { - // both phases are present, phase composition results from - // the gas <-> liquid equilibrium. This is - // the job of the "MiscibleMultiPhaseComposition" - // constraint solver - - // set the known mole fractions in the fluidState so that they - // can be used by the Miscible2pNCComposition constraint solver - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - { - fluidState.setMoleFraction(wPhaseIdx, compIdx, primaryVariables[compIdx]); - } - - Miscible2pNCComposition::solve(fluidState, - paramCache, - wPhaseIdx, //known phaseIdx - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - else if (phasePresence == nPhaseOnly){ - - Dune::FieldVector<Scalar, numComponents> moleFrac; - - - moleFrac[wCompIdx] = primaryVariables[switchIdx]; - - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - moleFrac[compIdx] = primaryVariables[compIdx]; - - - Scalar sumMoleFracNotGas = 0; - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - sumMoleFracNotGas+=moleFrac[compIdx]; - - sumMoleFracNotGas += moleFrac[wCompIdx]; - moleFrac[nCompIdx] = 1 - sumMoleFracNotGas; - - - // Set fluid state mole fractions - for (int compIdx=0; compIdx<numComponents; ++compIdx) - fluidState.setMoleFraction(nPhaseIdx, compIdx, moleFrac[compIdx]); - - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase2pNC" constraint solver - ComputeFromReferencePhase2pNC::solve(fluidState, - paramCache, - nPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - - } - else if (phasePresence == wPhaseOnly){ - // only the liquid phase is present, i.e. liquid phase - // composition is stored explicitly. - // extract _mass_ fractions in the gas phase - Dune::FieldVector<Scalar, numComponents> moleFrac; - - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - { - moleFrac[compIdx] = primaryVariables[compIdx]; - } - moleFrac[nCompIdx] = primaryVariables[switchIdx]; - Scalar sumMoleFracNotWater = 0; - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - { - sumMoleFracNotWater+=moleFrac[compIdx]; - } - sumMoleFracNotWater += moleFrac[nCompIdx]; - moleFrac[wCompIdx] = 1 -sumMoleFracNotWater; - - - // convert mass to mole fractions and set the fluid state - for (int compIdx=0; compIdx<numComponents; ++compIdx) - { - fluidState.setMoleFraction(wPhaseIdx, compIdx, moleFrac[compIdx]); - } - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase2pNC" constraint solver - ComputeFromReferencePhase2pNC::solve(fluidState, - paramCache, - wPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - paramCache.updateAll(fluidState); - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx); - Scalar mu = FluidSystem::viscosity(fluidState, paramCache, phaseIdx); - - fluidState.setDensity(phaseIdx, rho); - fluidState.setViscosity(phaseIdx, mu); - } - } - - /*! - * \brief Returns the phase state for the control-volume. - */ - const FluidState &fluidState() const - { return fluidState_; } - - /*! - * \brief Returns the saturation of a given phase within - * the control volume in \f$[-]\f$. - * - * \param phaseIdx The phase index - */ - Scalar saturation(int phaseIdx) const - { return fluidState_.saturation(phaseIdx); } - - /*! - * \brief Returns the mass density of a given phase within the - * control volume. - * - * \param phaseIdx The phase index - */ - Scalar density(int phaseIdx) const - { - if (phaseIdx < numPhases) - return fluidState_.density(phaseIdx); - - else - DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); - } - - /*! - * \brief Returns the mass density of a given phase within the - * control volume. - * - * \param phaseIdx The phase index - */ - Scalar molarDensity(int phaseIdx) const - { - if (phaseIdx < numPhases) - return fluidState_.molarDensity(phaseIdx); - - else - DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); - } - - /*! - * \brief Returns the effective pressure of a given phase within - * the control volume. - * - * \param phaseIdx The phase index - */ - Scalar pressure(int phaseIdx) const - { - return fluidState_.pressure(phaseIdx); - } - - /*! - * \brief Returns temperature inside the sub-control volume. - * - * Note that we assume thermodynamic equilibrium, i.e. the - * temperature of the rock matrix and of all fluid phases are - * identical. - */ - Scalar temperature() const - { return fluidState_.temperature(/*phaseIdx=*/0); } - - /*! - * \brief Returns the effective mobility of a given phase within - * the control volume. - * - * \param phaseIdx The phase index - */ - Scalar mobility(int phaseIdx) const - { - return mobility_[phaseIdx]; - } - - /*! - * \brief Returns the effective capillary pressure within the control volume - * in \f$[kg/(m*s^2)=N/m^2=Pa]\f$. - */ - Scalar capillaryPressure() const - { return fluidState_.pressure(FluidSystem::nPhaseIdx) - fluidState_.pressure(FluidSystem::wPhaseIdx); } - - /*! - * \brief Returns the average porosity within the control volume. - */ - Scalar porosity() const - { return porosity_; } - - - /*! - * \brief Returns the binary diffusion coefficients for a phase in \f$[m^2/s]\f$. - */ - Scalar diffCoeff(int phaseIdx, int compIdx) const - { return diffCoeff_[phaseIdx][compIdx]; } - - /*! - * \brief Returns the molarity of a component in the phase - * - * \param phaseIdx the index of the fluid phase - * \param compIdx the index of the component - */ - Scalar molarity(int phaseIdx, int compIdx) const // [moles/m^3] - { return this->fluidState_.molarity(phaseIdx, compIdx);} - - /*! - * \brief Returns the mass fraction of a component in the phase - * - * \param phaseIdx the index of the fluid phase - * \param compIdx the index of the component - */ - Scalar massFraction(int phaseIdx, int compIdx) const - { - return this->fluidState_.massFraction(phaseIdx, compIdx); - } - - /*! - * \brief Returns the mole fraction of a component in the phase - * - * \param phaseIdx the index of the fluid phase - * \param compIdx the index of the component - */ - Scalar moleFraction(int phaseIdx, int compIdx) const - { - return this->fluidState_.moleFraction(phaseIdx, compIdx); - } - -protected: - - static Scalar temperature_(const PrimaryVariables &priVars, - const Problem& problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int scvIdx) - { - return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); - } - - template<class ParameterCache> - static Scalar enthalpy_(const FluidState& fluidState, - const ParameterCache& paramCache, - int phaseIdx) - { - return 0; - } - - /*! - * \brief Called by update() to compute the energy related quantities - */ - void updateEnergy_(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx, - bool isOldSol) - { }; - - Scalar porosity_; //!< Effective porosity within the control volume - Scalar mobility_[numPhases]; //!< Effective mobility within the control volume - Scalar density_; - FluidState fluidState_; - Scalar theta_; - Scalar InitialPorosity_; - Scalar molWtPhase_[numPhases]; - Dune::FieldMatrix<Scalar, numPhases, numComponents> diffCoeff_; - -private: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } - -}; - -} // end namespace +#include <dumux/porousmediumflow/2pnc/implicit/volumevariables.hh> #endif diff --git a/dumux/implicit/2pncmin/2pncminfluxvariables.hh b/dumux/implicit/2pncmin/2pncminfluxvariables.hh index 3e0f7940f7..ce5cbcfceb 100644 --- a/dumux/implicit/2pncmin/2pncminfluxvariables.hh +++ b/dumux/implicit/2pncmin/2pncminfluxvariables.hh @@ -1,162 +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 Contains the data which is required to calculate - * all fluxes of components over a face of a finite volume for - * the two-phase two-component mineralization model fully implicit model. - */ -#ifndef DUMUX_2PNCMIN_FLUX_VARIABLES_HH -#define DUMUX_2PNCMIN_FLUX_VARIABLES_HH +#ifndef DUMUX_2PNCMIN_FLUX_VARIABLES_HH_OLD +#define DUMUX_2PNCMIN_FLUX_VARIABLES_HH_OLD -#include <dumux/common/math.hh> -#include <dumux/common/spline.hh> -#include <dumux/implicit/2pnc/2pncfluxvariables.hh> -#include "2pncminproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/2pncmin/implicit/fluxvariables.hh instead -namespace Dumux -{ - -/*! - * \ingroup TwoPNCMinModel - * \ingroup ImplicitFluxVariables - * \brief Contains the data which is required to calculate - * all fluxes of components over a face of a finite volume for - * the two-phase n-component mineralization fully implicit model. - * - * This means pressure and concentration gradients, phase densities at - * the integration point, etc. - */ - -template <class TypeTag> -class TwoPNCMinFluxVariables : public TwoPNCFluxVariables<TypeTag> -{ - typedef TwoPNCFluxVariables<TypeTag> ParentType; - typedef TwoPNCMinFluxVariables<TypeTag> ThisType; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - - typedef typename GridView::ctype CoordScalar; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - - enum { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld, - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - }; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename FVElementGeometry::SubControlVolume SCV; - typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; - - typedef Dune::FieldVector<CoordScalar, dimWorld> DimVector; - typedef Dune::FieldMatrix<CoordScalar, dim, dim> DimMatrix; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - wPhaseIdx = FluidSystem::wPhaseIdx, - nPhaseIdx = FluidSystem::nPhaseIdx, - wCompIdx = FluidSystem::wCompIdx, - }; - -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 sub-control-volume face - * \param elemVolVars The volume variables of the current element - * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face - */ - TwoPNCMinFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : ParentType(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) - { - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - this->density_[phaseIdx] = Scalar(0); - this->molarDensity_[phaseIdx] = Scalar(0); - this->potentialGrad_[phaseIdx] = Scalar(0); - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - this->massFractionGrad_[phaseIdx][compIdx] = Scalar(0); - this->moleFractionGrad_[phaseIdx][compIdx] = Scalar(0); - } - } - this->calculateGradients_(problem, element, elemVolVars); - this->calculateVelocities_(problem, element, elemVolVars); - this->calculateporousDiffCoeff_(problem, element, elemVolVars); - }; - -protected: - void calculateVelocities_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - const SpatialParams &spatialParams = problem.spatialParams(); - // multiply the pressure potential with the intrinsic permeability - DimMatrix K(0.0); - - for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) - { - const VolumeVariables &volVarsI = elemVolVars[this->face().i]; - const VolumeVariables &volVarsJ = elemVolVars[this->face().j]; - - auto K_i = spatialParams.intrinsicPermeability(element,this->fvGeometry_,this->face().i); - K_i *= volVarsI.permeabilityFactor(); - - auto K_j = spatialParams.intrinsicPermeability(element,this->fvGeometry_,this->face().j); - K_j *= volVarsJ.permeabilityFactor(); - - spatialParams.meanK(K,K_i,K_j); - - K.mv(this->potentialGrad_[phaseIdx], this->Kmvp_[phaseIdx]); - this->KmvpNormal_[phaseIdx] = - (this->Kmvp_[phaseIdx] * this->face().normal); - } - - // set the upstream and downstream vertices - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - this->upstreamIdx_[phaseIdx] = this->face().i; - this->downstreamIdx_[phaseIdx] = this->face().j; - - if (this->KmvpNormal_[phaseIdx] < 0) { - std::swap(this->upstreamIdx_[phaseIdx], - this->downstreamIdx_[phaseIdx]); - } - } - } -}; - -} // end namespace +#include <dumux/porousmediumflow/2pncmin/implicit/fluxvariables.hh> #endif diff --git a/dumux/implicit/2pncmin/2pncminindices.hh b/dumux/implicit/2pncmin/2pncminindices.hh index 8f4e103666..bf98e8edbf 100644 --- a/dumux/implicit/2pncmin/2pncminindices.hh +++ b/dumux/implicit/2pncmin/2pncminindices.hh @@ -1,48 +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_2PNCMIN_INDICES_HH_OLD +#define DUMUX_2PNCMIN_INDICES_HH_OLD -/*! - * \file - * \brief Defines the indices required for the two-phase n-component mineralization - * fully implicit model. - */ -#ifndef DUMUX_2PNCMIN_INDICES_HH -#define DUMUX_2PNCMIN_INDICES_HH +#warning this header is deprecated, use dumux/porousmediumflow/2pncmin/implicit/indices.hh instead -#include <dumux/implicit/2pnc/2pncindices.hh> - -namespace Dumux -{ -/*! - * \ingroup TwoPNCMinModel - * \ingroup ImplicitIndices - * \brief The indices for the isothermal two-phase n-component mineralization model. - * - * \tparam PVOffset The first index in a primary variable vector. - */ -template <class TypeTag, int PVOffset = 0> - class TwoPNCMinIndices: public TwoPNCIndices<TypeTag, PVOffset> -{ -}; - -// \} - -} +#include <dumux/porousmediumflow/2pncmin/implicit/indices.hh> #endif diff --git a/dumux/implicit/2pncmin/2pncminlocalresidual.hh b/dumux/implicit/2pncmin/2pncminlocalresidual.hh index 72299478f4..142ce3e389 100644 --- a/dumux/implicit/2pncmin/2pncminlocalresidual.hh +++ b/dumux/implicit/2pncmin/2pncminlocalresidual.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 of the Jacobian matrix for problems - * using the two-phase n-component mineralisation box model. - */ +#ifndef DUMUX_2PNCMIN_LOCAL_RESIDUAL_BASE_HH_OLD +#define DUMUX_2PNCMIN_LOCAL_RESIDUAL_BASE_HH_OLD -#ifndef DUMUX_2PNCMIN_LOCAL_RESIDUAL_BASE_HH -#define DUMUX_2PNCMIN_LOCAL_RESIDUAL_BASE_HH +#warning this header is deprecated, use dumux/porousmediumflow/2pncmin/implicit/localresidual.hh instead -#include "2pncminproperties.hh" -#include <dumux/implicit/2pnc/2pnclocalresidual.hh> - -namespace Dumux -{ -/*! - * \ingroup TwoPNCMinModel - * \ingroup ImplicitLocalResidual - * \brief Element-wise calculation of the Jacobian matrix for problems - * using the two-phase n-component mineralization fully implicit box model. - * - * This class is used to fill the gaps in ImplicitLocalResidual for the two-phase n-component flow. - */ -template<class TypeTag> -class TwoPNCMinLocalResidual: public TwoPNCLocalResidual<TypeTag> -{ -protected: - typedef TwoPNCLocalResidual<TypeTag> ParentType; - typedef TwoPNCMinLocalResidual<TypeTag> ThisType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - - - enum - { - numEq = GET_PROP_VALUE(TypeTag, NumEq), - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numSPhases = GET_PROP_VALUE(TypeTag, NumSPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - - replaceCompEqIdx = GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx), - - pressureIdx = Indices::pressureIdx, - switchIdx = Indices::switchIdx, - - wPhaseIdx = FluidSystem::wPhaseIdx, - nPhaseIdx = FluidSystem::nPhaseIdx, - - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx, - - conti0EqIdx = Indices::conti0EqIdx, - - wPhaseOnly = Indices::wPhaseOnly, - nPhaseOnly = Indices::nPhaseOnly, - bothPhases = Indices::bothPhases, - - plSg = TwoPNCFormulation::plSg, - pgSl = TwoPNCFormulation::pgSl, - formulation = GET_PROP_VALUE(TypeTag, Formulation) - }; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - -public: - /*! - * \brief Constructor. Sets the upwind weight. - */ - TwoPNCMinLocalResidual() - { - // 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 - this->massUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); - }; - - /*! - * \brief Evaluate the amount all conservation quantities - * (e.g. phase mass) within a sub-control volume. - * - * The result should be averaged over the volume (e.g. phase mass - * inside a sub control volume divided by the volume). - * In contrast to the 2pnc model, here, the storage of solid phases is included too. - * - * \param storage the mass of the component 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 - { - //call parenttype function - ParentType::computeStorage(storage, scvIdx, usePrevSol); - - const ElementVolumeVariables &elemVolVars = usePrevSol ? this->prevVolVars_() - : this->curVolVars_(); - const VolumeVariables &volVars = elemVolVars[scvIdx]; - - // Compute storage term of all solid (precipitated) phases (excluding the non-reactive matrix) - for (int phaseIdx = numPhases; phaseIdx < numPhases + numSPhases; ++phaseIdx) - { - int eqIdx = conti0EqIdx + numComponents-numPhases + phaseIdx; - storage[eqIdx] += volVars.precipitateVolumeFraction(phaseIdx)*volVars.molarDensity(phaseIdx); - } - - Valgrind::CheckDefined(storage); - } -}; -} // end namespace +#include <dumux/porousmediumflow/2pncmin/implicit/localresidual.hh> #endif diff --git a/dumux/implicit/2pncmin/2pncminmodel.hh b/dumux/implicit/2pncmin/2pncminmodel.hh index ac054fa6ee..7bfac2d257 100644 --- a/dumux/implicit/2pncmin/2pncminmodel.hh +++ b/dumux/implicit/2pncmin/2pncminmodel.hh @@ -1,551 +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 Adaption of the fully implicit box scheme to the two-phase n-component flow model. -*/ +#ifndef DUMUX_2PNCMIN_MODEL_HH_OLD +#define DUMUX_2PNCMIN_MODEL_HH_OLD -#ifndef DUMUX_2PNCMIN_MODEL_HH -#define DUMUX_2PNCMIN_MODEL_HH +#warning this header is deprecated, use dumux/porousmediumflow/2pncmin/implicit/model.hh instead -#include "2pncminproperties.hh" -#include "2pncminindices.hh" - -#include <dumux/material/constants.hh> - #include <dumux/implicit/2pnc/2pncmodel.hh> -#include "2pncminlocalresidual.hh" -#include <dumux/porousmediumflow/implicit/velocityoutput.hh> - -namespace Dumux -{ -/*! - * \ingroup TwoPNCMinModel - * \brief Adaption of the fully implicit scheme to the - * two-phase n-component fully implicit model. - * - * This model implements two-phase n-component flow of two compressible and - * partially miscible fluids \f$\alpha \in \{ w, n \}\f$ composed of the n components - * \f$\kappa \in \{ w, a,\cdots \}\f$. The standard multiphase Darcy - * approach is used as the equation for the conservation of momentum: - * \f[ - v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} - \left(\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) - * \f] - * - * By inserting this into the equations for the conservation of the - * components, one gets one transport equation for each component - * \f{eqnarray} - && \phi \frac{\partial (\sum_\alpha \varrho_\alpha X_\alpha^\kappa S_\alpha )} - {\partial t} - - \sum_\alpha \text{div} \left\{ \varrho_\alpha X_\alpha^\kappa - \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} - (\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g}) \right\} - \nonumber \\ \nonumber \\ - &-& \sum_\alpha \text{div} \left\{{\bf D_{\alpha, pm}^\kappa} \varrho_{\alpha} \text{grad}\, X^\kappa_{\alpha} \right\} - - \sum_\alpha q_\alpha^\kappa = 0 \qquad \kappa \in \{w, a,\cdots \} \, , - \alpha \in \{w, g\} - \f} - * - * All equations are discretized using a vertex-centered finite volume (box) - * or cell-centered finite volume scheme (this is not done for 2pnc approach yet, however possible) as - * spatial and the implicit Euler method as time discretization. - * - * By using constitutive relations for the capillary pressure \f$p_c = - * p_n - p_w\f$ and relative permeability \f$k_{r\alpha}\f$ and taking - * advantage of the fact that \f$S_w + S_n = 1\f$ and \f$X^\kappa_w + X^\kappa_n = 1\f$, the number of - * unknowns can be reduced to number of components. - * - * The used primary variables are, like in the two-phase model, either \f$p_w\f$ and \f$S_n\f$ - * or \f$p_n\f$ and \f$S_w\f$. The formulation which ought to be used can be - * specified by setting the <tt>Formulation</tt> property to either - * TwoPTwoCIndices::pWsN or TwoPTwoCIndices::pNsW. By - * default, the model uses \f$p_w\f$ and \f$S_n\f$. - * - * Moreover, the second primary variable depends on the phase state, since a - * primary variable switch is included. The phase state is stored for all nodes - * of the system. The model is uses mole fractions. - *Following cases can be distinguished: - * <ul> - * <li> Both phases are present: The saturation is used (either \f$S_n\f$ or \f$S_w\f$, dependent on the chosen <tt>Formulation</tt>), - * as long as \f$ 0 < S_\alpha < 1\f$</li>. - * <li> Only wetting phase is present: The mass fraction of, e.g., air in the wetting phase \f$X^a_w\f$ is used, - * as long as the maximum mass fraction is not exceeded (\f$X^a_w<X^a_{w,max}\f$)</li> - * <li> Only non-wetting phase is present: The mass fraction of, e.g., water in the non-wetting phase, \f$X^w_n\f$, is used, - * as long as the maximum mass fraction is not exceeded (\f$X^w_n<X^w_{n,max}\f$)</li> - * </ul> - */ - -template<class TypeTag> -class TwoPNCMinModel: public TwoPNCModel<TypeTag> -{ - typedef TwoPNCMinModel<TypeTag> ThisType; - typedef TwoPNCModel<TypeTag> ParentType; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - typedef Dumux::Constants<Scalar> Constant; - - enum { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld, - - numEq = GET_PROP_VALUE(TypeTag, NumEq), - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numSPhases = GET_PROP_VALUE(TypeTag, NumSPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - numSecComponents = GET_PROP_VALUE(TypeTag, NumSecComponents), - numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents), - - pressureIdx = Indices::pressureIdx, - switchIdx = Indices::switchIdx, - - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx, - - wPhaseOnly = Indices::wPhaseOnly, - nPhaseOnly = Indices::nPhaseOnly, - bothPhases = Indices::bothPhases, - - plSg = TwoPNCFormulation::plSg, - pgSl = TwoPNCFormulation::pgSl, - formulation = GET_PROP_VALUE(TypeTag, Formulation) - }; - - typedef typename GridView::template Codim<dim>::Entity Vertex; - typedef typename GridView::template Codim<0>::Entity Element; - - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - typedef typename GridView::ctype CoordScalar; - typedef Dune::FieldMatrix<CoordScalar, dimWorld, dimWorld> Tensor; - typedef Dune::FieldVector<Scalar, numPhases> PhasesVector; - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - -public: - - /*! - * \brief Append all quantities of interest which can be derived - * from the solution of the current time step to the VTK - * writer. - * - * \param sol The solution vector - * \param writer The writer for multi-file VTK datasets - */ - template<class MultiWriter> - //additional output of the permeability and the precipitate volume fractions - void addOutputVtkFields(const SolutionVector &sol, - MultiWriter &writer) - { - typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; - typedef Dune::BlockVector<Dune::FieldVector<double, dim> > VectorField; - - // get the number of degrees of freedom - unsigned numDofs = this->numDofs(); - - // create the required scalar fields - ScalarField *Sg = writer.allocateManagedBuffer (numDofs); - ScalarField *Sl = writer.allocateManagedBuffer (numDofs); - ScalarField *pg = writer.allocateManagedBuffer (numDofs); - ScalarField *pl = writer.allocateManagedBuffer (numDofs); - ScalarField *pc = writer.allocateManagedBuffer (numDofs); - ScalarField *rhoL = writer.allocateManagedBuffer (numDofs); - ScalarField *rhoG = writer.allocateManagedBuffer (numDofs); - ScalarField *mobL = writer.allocateManagedBuffer (numDofs); - ScalarField *mobG = writer.allocateManagedBuffer (numDofs); - ScalarField *phasePresence = writer.allocateManagedBuffer (numDofs); - ScalarField *temperature = writer.allocateManagedBuffer (numDofs); - ScalarField *poro = writer.allocateManagedBuffer (numDofs); - ScalarField *boxVolume = writer.allocateManagedBuffer (numDofs); - ScalarField *cellNum = writer.allocateManagedBuffer (numDofs); - ScalarField *permeabilityFactor = writer.allocateManagedBuffer (numDofs); - ScalarField *precipitateVolumeFraction[numSPhases] ; - - for (int i = 0; i < numSPhases; ++i) - { - precipitateVolumeFraction[i]= writer.allocateManagedBuffer (numDofs); - } - - ScalarField *massFraction[numPhases][numComponents]; - for (int i = 0; i < numPhases; ++i) - for (int j = 0; j < numComponents; ++j) - massFraction[i][j] = writer.allocateManagedBuffer(numDofs); - - ScalarField *molarity[numComponents]; - for (int j = 0; j < numComponents ; ++j) - molarity[j] = writer.allocateManagedBuffer(numDofs); - - ScalarField *Perm[dim]; - for (int j = 0; j < dim; ++j) //Permeability only in main directions xx and yy - Perm[j] = writer.allocateManagedBuffer(numDofs); - - *boxVolume = 0; - - VectorField *velocityN = writer.template allocateManagedBuffer<double, dim>(numDofs); - VectorField *velocityW = writer.template allocateManagedBuffer<double, dim>(numDofs); - ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - // initialize velocity fields - for (unsigned int i = 0; i < numDofs; ++i) - { - (*velocityN)[i] = Scalar(0); - (*velocityW)[i] = Scalar(0); - (*cellNum)[i] = Scalar(0.0); - } - } - - unsigned numElements = this->gridView_().size(0); - ScalarField *rank = - writer.allocateManagedBuffer (numElements); - - FVElementGeometry fvGeometry; - VolumeVariables volVars; - ElementVolumeVariables elemVolVars; - - for (const auto& element : Dune::elements(this->gridView_())) - { - int idx = this->problem_().elementMapper().index(element); - (*rank)[idx] = this->gridView_().comm().rank(); - fvGeometry.update(this->gridView_(), element); - - elemVolVars.update(this->problem_(), - element, - fvGeometry, - false /* oldSol? */); - - int numVerts = element.subEntities(dim); - - for (int i = 0; i < numVerts; ++i) - { - int globalIdx = this->vertexMapper().subIndex(element, i, dim); - volVars.update(sol[globalIdx], - this->problem_(), - element, - fvGeometry, - i, - false); - - (*Sg)[globalIdx] = volVars.saturation(nPhaseIdx); - (*Sl)[globalIdx] = volVars.saturation(wPhaseIdx); - (*pg)[globalIdx] = volVars.pressure(nPhaseIdx); - (*pl)[globalIdx] = volVars.pressure(wPhaseIdx); - (*pc)[globalIdx] = volVars.capillaryPressure(); - (*rhoL)[globalIdx] = volVars.density(wPhaseIdx); - (*rhoG)[globalIdx] = volVars.density(nPhaseIdx); - (*mobL)[globalIdx] = volVars.mobility(wPhaseIdx); - (*mobG)[globalIdx] = volVars.mobility(nPhaseIdx); - (*boxVolume)[globalIdx] += fvGeometry.subContVol[i].volume; - (*poro)[globalIdx] = volVars.porosity(); - - for (int sPhaseIdx = 0; sPhaseIdx < numSPhases; ++sPhaseIdx) - { - (*precipitateVolumeFraction[sPhaseIdx])[globalIdx] = volVars.precipitateVolumeFraction(sPhaseIdx + numPhases); - } - (*temperature)[globalIdx] = volVars.temperature(); - (*permeabilityFactor)[globalIdx] = volVars.permeabilityFactor(); - (*phasePresence)[globalIdx] = this->staticDat_[globalIdx].phasePresence; - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - (*massFraction[phaseIdx][compIdx])[globalIdx]= volVars.massFraction(phaseIdx,compIdx); - - Valgrind::CheckDefined((*massFraction[phaseIdx][compIdx])[globalIdx]); - - } - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - (*molarity[compIdx])[globalIdx] = (volVars.molarity(wPhaseIdx, compIdx)); - - Tensor K = this->perm_(this->problem_().spatialParams().intrinsicPermeability(element, fvGeometry, i)); - - for (int j = 0; j<dim; ++j) - (*Perm[j])[globalIdx] = K[j][j] * volVars.permeabilityFactor(); - }; - - // velocity output - if(velocityOutput.enableOutput()){ - velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); - velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); - } - } // loop over element - - writer.attachVertexData(*Sg, "Sg"); - writer.attachVertexData(*Sl, "Sl"); - writer.attachVertexData(*pg, "pg"); - writer.attachVertexData(*pl, "pl"); - writer.attachVertexData(*pc, "pc"); - writer.attachVertexData(*rhoL, "rhoL"); - writer.attachVertexData(*rhoG, "rhoG"); - writer.attachVertexData(*mobL, "mobL"); - writer.attachVertexData(*mobG, "mobG"); - writer.attachVertexData(*poro, "porosity"); - writer.attachVertexData(*permeabilityFactor, "permeabilityFactor"); - writer.attachVertexData(*temperature, "temperature"); - writer.attachVertexData(*phasePresence, "phase presence"); - writer.attachVertexData(*boxVolume, "boxVolume"); - - - for (int i = 0; i < numSPhases; ++i) - { - std::ostringstream oss; - oss << "precipitateVolumeFraction_" - << FluidSystem::phaseName(numPhases + i); - writer.attachDofData(*precipitateVolumeFraction[i], oss.str().c_str(), isBox); - } - - writer.attachVertexData(*Perm[0], "Kxx"); - if (dim >= 2) - writer.attachVertexData(*Perm[1], "Kyy"); - if (dim == 3) - writer.attachVertexData(*Perm[2], "Kzz"); - - for (int i = 0; i < numPhases; ++i) - { - for (int j = 0; j < numComponents; ++j) - { - std::ostringstream oss; - oss << "X^" - << FluidSystem::phaseName(i) - << "_" - << FluidSystem::componentName(j); - writer.attachVertexData(*massFraction[i][j], oss.str().c_str()); - } - } - - for (int j = 0; j < numComponents; ++j) - { - std::ostringstream oss; - oss << "m^w_" - << FluidSystem::componentName(j); - writer.attachVertexData(*molarity[j], oss.str().c_str()); - } - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - writer.attachDofData(*velocityW, "velocityW", isBox, dim); - writer.attachDofData(*velocityN, "velocityN", isBox, dim); - } - - writer.attachCellData(*rank, "process rank"); - } - - /*! - * \brief Update the static data of all vertices in the grid. - * - * \param curGlobalSol The current global solution - * \param oldGlobalSol The previous global solution - */ - void updateStaticData(SolutionVector &curGlobalSol, - const SolutionVector &oldGlobalSol) - { - bool wasSwitched = false; - - for (unsigned i = 0; i < this->staticDat_.size(); ++i) - this->staticDat_[i].visited = false; - - FVElementGeometry fvGeometry; - static VolumeVariables volVars; - for (const auto& element : Dune::elements(this->gridView_())) - { - fvGeometry.update(this->gridView_(), element); - for (int i = 0; i < fvGeometry.numScv; ++i) - { - int globalIdx = this->vertexMapper().subIndex(element, i, dim); - - if (this->staticDat_[globalIdx].visited) - continue; - - this->staticDat_[globalIdx].visited = true; - volVars.update(curGlobalSol[globalIdx], - this->problem_(), - element, - fvGeometry, - i, - false); - const GlobalPosition &global = element.geometry().corner(i); - if (primaryVarSwitch_(curGlobalSol, - volVars, - globalIdx, - global)) - { wasSwitched = true; - } - } - } - - // make sure that if there was a variable switch in an - // other partition we will also set the switch flag - // for our partition. - if (this->gridView_().comm().size() > 1) - wasSwitched = this->gridView_().comm().max(wasSwitched); - - setSwitched_(wasSwitched); - } -protected: - - /*! - * \brief Set whether there was a primary variable switch after in - * the last timestep. - */ - void setSwitched_(bool yesno) - { - switchFlag_ = yesno; - } - - /*! - * \copydoc 2pnc::primaryVarSwitch_ - */ - bool primaryVarSwitch_(SolutionVector &globalSol, - const VolumeVariables &volVars, int globalIdx, - const GlobalPosition &globalPos) - { - // evaluate primary variable switch - bool wouldSwitch = false; - int phasePresence = this->staticDat_[globalIdx].phasePresence; - int newPhasePresence = phasePresence; - - //check if a primary variable switch is necessary - if (phasePresence == bothPhases) - { - Scalar Smin = 0.0; //saturation threshold - if (this->staticDat_[globalIdx].wasSwitched) - Smin = -0.01; - - //if saturation of liquid phase is smaller 0 switch - if (volVars.saturation(wPhaseIdx) <= Smin) - { - wouldSwitch = true; - //liquid phase has to disappear - std::cout << "Liquid Phase disappears at vertex " << globalIdx - << ", coordinated: " << globalPos << ", Sl: " - << volVars.saturation(wPhaseIdx) << std::endl; - newPhasePresence = nPhaseOnly; - - //switch not depending on formulation - //switch "Sl" to "xgH20" - globalSol[globalIdx][switchIdx] - = volVars.moleFraction(nPhaseIdx, wCompIdx /*H2O*/); - //Here unlike 2pnc model we do not switch all components to to mole fraction in gas phase - } - //if saturation of gas phase is smaller than 0 switch - else if (volVars.saturation(nPhaseIdx) <= Smin) - { - wouldSwitch = true; - //gas phase has to disappear - std::cout << "Gas Phase disappears at vertex " << globalIdx - << ", coordinated: " << globalPos << ", Sg: " - << volVars.saturation(nPhaseIdx) << std::endl; - newPhasePresence = wPhaseOnly; - - //switch "Sl" to "xlN2" - globalSol[globalIdx][switchIdx] - = volVars.moleFraction(wPhaseIdx, nCompIdx /*N2*/); - } - } - else if (phasePresence == nPhaseOnly) - { - Scalar sumxl = 0; - //Calculate sum of mole fractions (water and air) in the hypothetical liquid phase - //WARNING: Here numComponents is replaced by numMajorComponents as the solutes - //are only present in the liquid phase and cannot condense as the liquid (water). - for (int compIdx = 0; compIdx < numComponents; compIdx++) - { - sumxl += volVars.moleFraction(wPhaseIdx, compIdx); - } - Scalar xlmax = 1.0; - if (sumxl > xlmax) - wouldSwitch = true; - if (this->staticDat_[globalIdx].wasSwitched) - xlmax *=1.02; - - //if the sum of the mole fractions would be larger than - //1, wetting phase appears - if (sumxl/*sum of mole fractions*/ > xlmax/*1*/) - { - // liquid phase appears - std::cout << "Liquid Phase appears at vertex " << globalIdx - << ", coordinated: " << globalPos << ", sumxl: " - << sumxl << std::endl; - newPhasePresence = bothPhases; - if (formulation == pgSl) - globalSol[globalIdx][switchIdx] = 0.0; - else if (formulation == plSg) - globalSol[globalIdx][switchIdx] = 1.0; - //Here unlike 2pnc model we do not switch all components to to mole fraction in gas phase - } - } - else if (phasePresence == wPhaseOnly) - { - Scalar xgmax = 1; - Scalar sumxg = 0; - //Calculate sum of mole fractions in the hypothetical gas phase - for (int compIdx = 0; compIdx < numComponents; compIdx++) - { - sumxg += volVars.moleFraction(nPhaseIdx, compIdx); - } - if (sumxg > xgmax) - wouldSwitch = true; - if (this->staticDat_[globalIdx].wasSwitched) - xgmax *=1.02; - //liquid phase appears if sum is larger than one - if (sumxg > xgmax) - { - std::cout << "Gas Phase appears at vertex " << globalIdx - << ", coordinated: " << globalPos << ", sumxg: " - << sumxg << std::endl; - newPhasePresence = bothPhases; - //saturation of the liquid phase set to 0.9999 (if formulation pgSl and vice versa) - if (formulation == pgSl) - globalSol[globalIdx][switchIdx] = 0.999; - else if (formulation == plSg) - globalSol[globalIdx][switchIdx] = 0.001; - - } - } - this->staticDat_[globalIdx].phasePresence = newPhasePresence; - this->staticDat_[globalIdx].wasSwitched = wouldSwitch; - return phasePresence != newPhasePresence; - } - // parameters given in constructor - bool switchFlag_; -}; - -} - -#include "2pncminpropertydefaults.hh" +#include <dumux/porousmediumflow/2pncmin/implicit/model.hh> #endif diff --git a/dumux/implicit/2pncmin/2pncminproperties.hh b/dumux/implicit/2pncmin/2pncminproperties.hh index 9f410f690c..623b90b31e 100644 --- a/dumux/implicit/2pncmin/2pncminproperties.hh +++ b/dumux/implicit/2pncmin/2pncminproperties.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/>. * - *****************************************************************************/ -/*! - * \ingroup Properties - * \ingroup ImplicitProperties - * \ingroup TwoPNCMinModel - * - * \file - * - * \brief Defines the properties required for the two-phase n-component mineralization - * fully implicit model. - */ -#ifndef DUMUX_2PNCMIN_PROPERTIES_HH -#define DUMUX_2PNCMIN_PROPERTIES_HH +#ifndef DUMUX_2PNCMIN_PROPERTIES_HH_OLD +#define DUMUX_2PNCMIN_PROPERTIES_HH_OLD -#include <dumux/implicit/2pnc/2pncproperties.hh> +#warning this header is deprecated, use dumux/porousmediumflow/2pncmin/implicit/properties.hh instead -namespace Dumux -{ - -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tag for the isothermal two phase n component mineralisation problems -NEW_TYPE_TAG(TwoPNCMin, INHERITS_FROM(TwoPNC)); -NEW_TYPE_TAG(BoxTwoPNCMin, INHERITS_FROM(BoxModel, TwoPNCMin)); -NEW_TYPE_TAG(CCTwoPNCMin, INHERITS_FROM(CCModel, TwoPNCMin)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// - -NEW_PROP_TAG(NumSPhases); //!< Number of solid phases in the system -NEW_PROP_TAG(NumFSPhases); //!< Number of fluid and solid phases in the system -NEW_PROP_TAG(NumSComponents); //!< Number of solid components in the system -NEW_PROP_TAG(NumPSComponents); //!< Number of fluid and solid components in the system -NEW_PROP_TAG(NumTraceComponents); //!< Number of trace fluid components which are not considered in the calculation of the phase density -NEW_PROP_TAG(NumSecComponents); //!< Number of secondary components which are not primary variables -NEW_PROP_TAG(TwoPNCMinIndices); //!< Enumerations for the 2pncMin models -NEW_PROP_TAG(useSalinity); //!< Determines if salinity is used -NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient - -} -} +#include <dumux/porousmediumflow/2pncmin/implicit/properties.hh> #endif diff --git a/dumux/implicit/2pncmin/2pncminpropertydefaults.hh b/dumux/implicit/2pncmin/2pncminpropertydefaults.hh index 63a3b03439..64cf62f4b3 100644 --- a/dumux/implicit/2pncmin/2pncminpropertydefaults.hh +++ b/dumux/implicit/2pncmin/2pncminpropertydefaults.hh @@ -1,143 +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 TwoPNCMinModel - * \file - * - * \brief Defines default values for most properties required by the - * two-phase n-component mineralization fully implicit model. - */ -#ifndef DUMUX_2PNCMIN_PROPERTY_DEFAULTS_HH -#define DUMUX_2PNCMIN_PROPERTY_DEFAULTS_HH +#ifndef DUMUX_2PNCMIN_PROPERTY_DEFAULTS_HH_OLD +#define DUMUX_2PNCMIN_PROPERTY_DEFAULTS_HH_OLD -#include "2pncminindices.hh" -#include "2pncminmodel.hh" -#include "2pncminindices.hh" -#include "2pncminfluxvariables.hh" -#include "2pncminvolumevariables.hh" -#include "2pncminproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/2pncmin/implicit/propertydefaults.hh instead -#include <dumux/implicit/2pnc/2pncnewtoncontroller.hh> -#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> -#include <dumux/material/spatialparams/implicitspatialparams.hh> - -namespace Dumux -{ - -namespace Properties { -////////////////////////////////////////////////////////////////// -// Property values -////////////////////////////////////////////////////////////////// - -/*! - * \brief Set the property for the number of secondary components. - * Secondary components are components calculated from - * primary components by equilibrium relations and - * do not have mass balance equation on their own. - * These components are important in the context of bio-mineralization applications. - * We just forward the number from the fluid system - * - */ -SET_PROP(TwoPNCMin, NumSecComponents) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numSecComponents; - -}; -/*! - * \brief Set the property for the number of solid phases, excluding the non-reactive matrix. - * - * We just forward the number from the fluid system - * - */ -SET_PROP(TwoPNCMin, NumSPhases) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numSPhases; -}; - -/*! - * \brief Set the property for the number of equations. - * For each component and each precipitated mineral/solid phase one equation has to - * be solved. - */ -SET_PROP(TwoPNCMin, NumEq) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; - -public: - static const int value = FluidSystem::numComponents + FluidSystem::numSPhases; -}; - -/*! - * \brief The fluid state which is used by the volume variables to - * store the thermodynamic state. This should be chosen - * appropriately for the model ((non-)isothermal, equilibrium, ...). - * This can be done in the problem. - */ -SET_PROP(TwoPNCMin, 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; -}; - -//! Use the 2pncmin local residual operator -SET_TYPE_PROP(TwoPNCMin, - LocalResidual, - TwoPNCMinLocalResidual<TypeTag>); - -//! the Model property -SET_TYPE_PROP(TwoPNCMin, Model, TwoPNCMinModel<TypeTag>); - -//! the VolumeVariables property -SET_TYPE_PROP(TwoPNCMin, VolumeVariables, TwoPNCMinVolumeVariables<TypeTag>); - -//! the FluxVariables property -SET_TYPE_PROP(TwoPNCMin, FluxVariables, TwoPNCMinFluxVariables<TypeTag>); - -//! The indices required by the isothermal 2pNcMin model -SET_TYPE_PROP(TwoPNCMin, Indices, TwoPNCMinIndices <TypeTag, /*PVOffset=*/0>); - -//! disable useSalinity for the calculation of osmotic pressure by default -SET_BOOL_PROP(TwoPNCMin, useSalinity, false); - - -//! default value for the forchheimer coefficient -// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. -// Actually the Forchheimer coefficient is also a function of the dimensions of the -// porous medium. Taking it as a constant is only a first approximation -// (Nield, Bejan, Convection in porous media, 2006, p. 10) -SET_SCALAR_PROP(TwoPNCMin, SpatialParamsForchCoeff, 0.55); - -} - -} +#include <dumux/porousmediumflow/2pncmin/implicit/propertydefaults.hh> #endif diff --git a/dumux/implicit/2pncmin/2pncminvolumevariables.hh b/dumux/implicit/2pncmin/2pncminvolumevariables.hh index 4e11fd1f48..1c31f964a2 100644 --- a/dumux/implicit/2pncmin/2pncminvolumevariables.hh +++ b/dumux/implicit/2pncmin/2pncminvolumevariables.hh @@ -1,549 +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 Contains the quantities which are constant within a - * finite volume in the two-phase, n-component mineralization model. - */ -#ifndef DUMUX_2PNCMin_VOLUME_VARIABLES_HH -#define DUMUX_2PNCMin_VOLUME_VARIABLES_HH +#ifndef DUMUX_2PNCMin_VOLUME_VARIABLES_HH_OLD +#define DUMUX_2PNCMin_VOLUME_VARIABLES_HH_OLD -#include <dumux/implicit/model.hh> -#include <dumux/material/fluidstates/compositionalfluidstate.hh> -#include <dumux/common/math.hh> -#include <vector> -#include <iostream> +#warning this header is deprecated, use dumux/porousmediumflow/2pncmin/implicit/volumevariables.hh instead -#include "2pncminproperties.hh" -#include "2pncminindices.hh" -#include <dumux/material/constraintsolvers/computefromreferencephase2pncmin.hh> -#include <dumux/material/constraintsolvers/miscible2pnccomposition.hh> -#include <dumux/implicit/2pnc/2pncvolumevariables.hh> - -namespace Dumux -{ - -/*! - * \ingroup TwoPNCMinModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are are constant within a - * finite volume in the two-phase, n-component model. - */ -template <class TypeTag> -class TwoPNCMinVolumeVariables : public TwoPNCVolumeVariables<TypeTag> -{ - typedef TwoPNCVolumeVariables<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum - { - dim = GridView::dimension, - dimWorld=GridView::dimensionworld, - - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numSPhases = GET_PROP_VALUE(TypeTag, NumSPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents), - - // formulations - formulation = GET_PROP_VALUE(TypeTag, Formulation), - plSg = TwoPNCFormulation::plSg, - pgSl = TwoPNCFormulation::pgSl, - - // phase indices - wPhaseIdx = FluidSystem::wPhaseIdx, - nPhaseIdx = FluidSystem::nPhaseIdx, - - // component indices - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx, - - // phase presence enums - nPhaseOnly = Indices::nPhaseOnly, - wPhaseOnly = Indices::wPhaseOnly, - bothPhases = Indices::bothPhases, - - // primary variable indices - pressureIdx = Indices::pressureIdx, - switchIdx = Indices::switchIdx, - - useSalinity = GET_PROP_VALUE(TypeTag, useSalinity) - }; - - typedef typename GridView::template Codim<0>::Entity Element; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - typedef typename Grid::ctype CoordScalar; - typedef Dumux::Miscible2pNCComposition<Scalar, FluidSystem> Miscible2pNCComposition; - typedef Dumux::ComputeFromReferencePhase2pNCMin<Scalar, FluidSystem> ComputeFromReferencePhase2pNCMin; - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; -public: - - typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; - - /*! - * \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); - - completeFluidState(priVars, problem, element, fvGeometry, scvIdx, this->fluidState_, isOldSol); - - ///////////// - // calculate the remaining quantities - ///////////// - - // porosity evaluation - initialPorosity_ = problem.spatialParams().porosity(element, fvGeometry, scvIdx); - minimumPorosity_ = problem.spatialParams().porosityMin(element, fvGeometry, scvIdx); - - - sumPrecipitates_ = 0.0; - for(int sPhaseIdx = 0; sPhaseIdx < numSPhases; ++sPhaseIdx) - { - precipitateVolumeFraction_[sPhaseIdx] = priVars[numComponents + sPhaseIdx]; - sumPrecipitates_+= precipitateVolumeFraction_[sPhaseIdx]; - } - -// for(int sPhaseIdx = 0; sPhaseIdx < numSPhases; ++sPhaseIdx) -// { -// Chemistry chemistry; // the non static functions can not be called without abject -// saturationIdx_[sPhaseIdx] = chemistry.omega(sPhaseIdx); -// } -// TODO/FIXME: The salt crust porosity is not clearly defined. However form literature review it is -// found that the salt crust have porosity of approx. 10 %. Thus we restrict the decrease in porosity -// to this limit. Moreover in the Problem files the precipitation should also be made dependent on local -// porosity value, as the porous media media properties change related to salt precipitation will not be -// accounted otherwise. - -// this->porosity_ = initialPorosity_ - sumPrecipitates_; - - this->porosity_ = std::max(minimumPorosity_, std::max(0.0, initialPorosity_ - sumPrecipitates_)); - - salinity_= 0.0; - moleFractionSalinity_ = 0.0; - for (int compIdx = numMajorComponents; compIdx< numComponents; compIdx++) //sum of the mass fraction of the components - { - if(this->fluidState_.moleFraction(wPhaseIdx, compIdx)> 0) - { - salinity_+= this->fluidState_.massFraction(wPhaseIdx, compIdx); - moleFractionSalinity_ += this->fluidState_.moleFraction(wPhaseIdx, compIdx); - } - } - -// TODO/FIXME: Different relations for the porosoty-permeability changes are given here. We have to fins a way -// so that one can select the relation form the input file. - - // kozeny-Carman relation - permeabilityFactor_ = std::pow(((1-initialPorosity_)/(1-this->porosity_)),2) - * std::pow((this->porosity_/initialPorosity_),3); - - // Verma-Pruess relation -// permeabilityFactor_ = 100 * std::pow(((this->porosity_/initialPorosity_)-0.9),2); - - // Modified Fair-Hatch relation with final porosity set to 0.2 and E1=1 -// permeabilityFactor_ = std::pow((this->porosity_/initialPorosity_),3) -// * std::pow((std::pow((1 - initialPorosity_),2/3))+(std::pow((0.2 - initialPorosity_),2/3)),2) -// / std::pow((std::pow((1 -this->porosity_),2/3))+(std::pow((0.2 -this->porosity_),2/3)),2); - - //Timur relation with residual water saturation set to 0.001 -// permeabilityFactor_ = 0.136 * (std::pow(this->porosity_,4.4)) / (2000 * (std::pow(0.001,2))); - - //Timur relation1 with residual water saturation set to 0.001 -// permeabilityFactor_ = 0.136 * (std::pow(this->porosity_,4.4)) / (200000 * (std::pow(0.001,2))); - - - //Bern. relation - // permeabilityFactor_ = std::pow((this->porosity_/initialPorosity_),8); - - //Tixier relation with residual water saturation set to 0.001 - //permeabilityFactor_ = (std::pow((250 * (std::pow(this->porosity_,3)) / 0.001),2)) / initialPermeability_; - - //Coates relation with residual water saturation set to 0.001 - //permeabilityFactor_ = (std::pow((100 * (std::pow(this->porosity_,2)) * (1-0.001) / 0.001,2))) / initialPermeability_ ; - - - // energy related quantities not contained in the fluid state - //asImp_().updateEnergy_(priVars, problem,element, fvGeometry, scvIdx, isOldSol); - } - - /*! - * \copydoc ImplicitModel::completeFluidState - * \param isOldSol Specifies whether this is the previous solution or the current one - */ - static void completeFluidState(const PrimaryVariables& priVars, - const Problem& problem, - const Element& element, - const FVElementGeometry& fvGeometry, - int scvIdx, - FluidState& fluidState, - bool isOldSol = false) - - { - Scalar t = Implementation::temperature_(priVars, problem, element,fvGeometry, scvIdx); - fluidState.setTemperature(t); - - int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); - int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); - - ///////////// - // set the saturations - ///////////// - - Scalar Sg; - if (phasePresence == nPhaseOnly) - Sg = 1.0; - else if (phasePresence == wPhaseOnly) { - Sg = 0.0; - } - else if (phasePresence == bothPhases) { - if (formulation == plSg) - Sg = priVars[switchIdx]; - else if (formulation == pgSl) - Sg = 1.0 - priVars[switchIdx]; - else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); - } - else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); - fluidState.setSaturation(nPhaseIdx, Sg); - fluidState.setSaturation(wPhaseIdx, 1.0 - Sg); - - ///////////// - // set the pressures of the fluid phases - ///////////// - - // calculate capillary pressure - const MaterialLawParams &materialParams = problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); - Scalar pc = MaterialLaw::pc(materialParams, 1 - Sg); - - // extract the pressures - if (formulation == plSg) { - fluidState.setPressure(wPhaseIdx, priVars[pressureIdx]); - fluidState.setPressure(nPhaseIdx, priVars[pressureIdx] + pc); - } - else if (formulation == pgSl) { - fluidState.setPressure(nPhaseIdx, priVars[pressureIdx]); - fluidState.setPressure(wPhaseIdx, priVars[pressureIdx] - pc); - } - else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); - - ///////////// - // calculate the phase compositions - ///////////// - - typename FluidSystem::ParameterCache paramCache; - - // now comes the tricky part: calculate phase composition - if (phasePresence == bothPhases) { - // both phases are present, phase composition results from - // the gas <-> liquid equilibrium. This is - // the job of the "MiscibleMultiPhaseComposition" - // constraint solver - - // set the known mole fractions in the fluidState so that they - // can be used by the Miscible2pNcComposition constraint solver - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - { - fluidState.setMoleFraction(wPhaseIdx, compIdx, priVars[compIdx]); - } - - Miscible2pNCComposition::solve(fluidState, - paramCache, - wPhaseIdx, //known phaseIdx - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - else if (phasePresence == nPhaseOnly){ - - Dune::FieldVector<Scalar, numComponents> moleFrac; - Dune::FieldVector<Scalar, numComponents> fugCoeffL; - Dune::FieldVector<Scalar, numComponents> fugCoeffG; - - for (int compIdx=0; compIdx<numComponents; ++compIdx) - { - fugCoeffL[compIdx] = FluidSystem::fugacityCoefficient(fluidState, - paramCache, - wPhaseIdx, - compIdx); - fugCoeffG[compIdx] = FluidSystem::fugacityCoefficient(fluidState, - paramCache, - nPhaseIdx, - compIdx); - } - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - moleFrac[compIdx] = (priVars[compIdx]*fugCoeffL[compIdx]*fluidState.pressure(wPhaseIdx)) - /(fugCoeffG[compIdx]*fluidState.pressure(nPhaseIdx)); - - moleFrac[wCompIdx] = priVars[switchIdx]; - Scalar sumMoleFracNotGas = 0; - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - { - sumMoleFracNotGas+=moleFrac[compIdx]; - } - sumMoleFracNotGas += moleFrac[wCompIdx]; - moleFrac[nCompIdx] = 1 - sumMoleFracNotGas; - -// typedef Dune::FieldMatrix<Scalar, numComponents, numComponents> Matrix; -// typedef Dune::FieldVector<Scalar, numComponents> Vector; - - - // Set fluid state mole fractions - for (int compIdx=0; compIdx<numComponents; ++compIdx) - { - fluidState.setMoleFraction(nPhaseIdx, compIdx, moleFrac[compIdx]); - } - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase2pNc" constraint solver - ComputeFromReferencePhase2pNCMin::solve(fluidState, - paramCache, - nPhaseIdx, - nPhaseOnly, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - - } - else if (phasePresence == wPhaseOnly){ - - // only the liquid phase is present, i.e. liquid phase - // composition is stored explicitly. - // extract _mass_ fractions in the gas phase - Dune::FieldVector<Scalar, numComponents> moleFrac; - - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - { - moleFrac[compIdx] = priVars[compIdx]; - } - moleFrac[nCompIdx] = priVars[switchIdx]; - Scalar sumMoleFracNotWater = 0; - for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) - { - sumMoleFracNotWater+=moleFrac[compIdx]; - } - sumMoleFracNotWater += moleFrac[nCompIdx]; - moleFrac[wCompIdx] = 1 -sumMoleFracNotWater; - -// convert mass to mole fractions and set the fluid state - for (int compIdx=0; compIdx<numComponents; ++compIdx) - { - fluidState.setMoleFraction(wPhaseIdx, compIdx, moleFrac[compIdx]); - } - -// calculate the composition of the remaining phases (as -// well as the densities of all phases). this is the job -// of the "ComputeFromReferencePhase2pNc" constraint solver - ComputeFromReferencePhase2pNCMin::solve(fluidState, - paramCache, - wPhaseIdx, - wPhaseOnly, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - paramCache.updateAll(fluidState); - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - Scalar h = Implementation::enthalpy_(fluidState, paramCache, phaseIdx); - fluidState.setEnthalpy(phaseIdx, h); - } - } - /*! - * \brief Returns the volume fraction of the precipitate (solid phase) - * for the given phaseIdx - * - * \param phaseIdx the index of the solid phase - */ - Scalar precipitateVolumeFraction(int phaseIdx) const - { return precipitateVolumeFraction_[phaseIdx - numPhases]; } - - /*! - * \brief Returns the inital porosity of the - * pure, precipitate-free porous medium - */ - Scalar initialPorosity() const - { return initialPorosity_;} - - /*! - * \brief Returns the inital permeability of the - * pure, precipitate-free porous medium - */ - Scalar initialPermeability() const - { return initialPermeability_;} - - /*! - * \brief Returns the factor for the reduction of the initial permeability - * due precipitates in the porous medium - */ - Scalar permeabilityFactor() const - { return permeabilityFactor_; } - -// /*! -// * \brief Returns the mole fraction of a component in the phase -// * -// * \param phaseIdx the index of the fluid phase -// * \param compIdx the index of the component -// */ -// Scalar moleFraction(int phaseIdx, int compIdx) const -// { -// return this->fluidState_.moleFraction(phaseIdx, compIdx); -// } - - /*! - * \brief Returns the mole fraction of the salinity in the liquid phase - */ - Scalar moleFracSalinity() const - { - return moleFractionSalinity_; - } - - /*! - * \brief Returns the salinity (mass fraction) in the liquid phase - */ - Scalar salinity() const - { - return salinity_; - } - - /*! - * \brief Returns the density of the phase for all fluid and solid phases - * - * \param phaseIdx the index of the fluid phase - */ - Scalar density(int phaseIdx) const - { - if (phaseIdx < numPhases) - return this->fluidState_.density(phaseIdx); - else if (phaseIdx >= numPhases) - return FluidSystem::precipitateDensity(phaseIdx); - else - DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); - } - /*! - * \brief Returns the mass density of a given phase within the - * control volume. - * - * \param phaseIdx The phase index - */ - Scalar molarDensity(int phaseIdx) const - { - if (phaseIdx < numPhases) - return this->fluidState_.molarDensity(phaseIdx); - else if (phaseIdx >= numPhases) - return FluidSystem::precipitateMolarDensity(phaseIdx); - else - DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); - } - - /*! - * \brief Returns the molality of a component in the phase - * - * \param phaseIdx the index of the fluid phase - * \param compIdx the index of the component - * molality=\frac{n_{component}}{m_{solvent}} - * =\frac{n_{component}}{n_{solvent}*M_{solvent}} - * compIdx of the main component (solvent) in the - * phase is equal to the phaseIdx - */ - Scalar molality(int phaseIdx, int compIdx) const // [moles/Kg] - { return this->fluidState_.moleFraction(phaseIdx, compIdx) - /(fluidState_.moleFraction(phaseIdx, phaseIdx) - * FluidSystem::molarMass(phaseIdx));} - -protected: - friend class TwoPNCVolumeVariables<TypeTag>; - static Scalar temperature_(const PrimaryVariables &priVars, - const Problem& problem, - const Element &element, - const FVElementGeometry &fvGeometry, - int scvIdx) - { - return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); - } - - template<class ParameterCache> - static Scalar enthalpy_(const FluidState& fluidState, - const ParameterCache& paramCache, - int phaseIdx) - { - return 0; - } - - /*! - * \brief Update all quantities for a given control volume. - * - * \param priVars The solution primary variables - * \param problem The problem - * \param element The element - * \param fvGeometry Evaluate function with solution of current or previous time step - * \param scvIdx The local index of the SCV (sub-control volume) - * \param isOldSol Evaluate function with solution of current or previous time step - */ - void updateEnergy_(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx, - bool isOldSol) - { }; - - Scalar precipitateVolumeFraction_[numSPhases]; -// Scalar saturationIdx_[numSPhases]; - Scalar permeabilityFactor_; - Scalar initialPorosity_; - Scalar initialPermeability_; - Scalar minimumPorosity_; - Scalar sumPrecipitates_; - Scalar salinity_; - Scalar moleFractionSalinity_; - FluidState fluidState_; - -private: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } -}; - -} // end namespace +#include <dumux/porousmediumflow/2pncmin/implicit/volumevariables.hh> #endif diff --git a/dumux/implicit/3p3c/3p3cfluxvariables.hh b/dumux/implicit/3p3c/3p3cfluxvariables.hh index f3c3d62d8d..25830baebb 100644 --- a/dumux/implicit/3p3c/3p3cfluxvariables.hh +++ b/dumux/implicit/3p3c/3p3cfluxvariables.hh @@ -1,386 +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 - * all fluxes of components over a face of a finite volume for - * the three-phase three-component model. - */ -#ifndef DUMUX_3P3C_FLUX_VARIABLES_HH -#define DUMUX_3P3C_FLUX_VARIABLES_HH +#ifndef DUMUX_3P3C_FLUX_VARIABLES_HH_OLD +#define DUMUX_3P3C_FLUX_VARIABLES_HH_OLD -#include <dumux/common/math.hh> -#include <dumux/common/spline.hh> +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/fluxvariables.hh instead -#include "3p3cproperties.hh" - -namespace Dumux -{ - -/*! - * \ingroup ThreePThreeCModel - * \ingroup ImplicitFluxVariables - * \brief This template class contains the data which is required to - * calculate all fluxes of components over a face of a finite - * volume for the three-phase three-component model. - * - * This means pressure and concentration gradients, phase densities at - * the integration point, etc. - */ -template <class TypeTag> -class ThreePThreeCFluxVariables : public GET_PROP_TYPE(TypeTag, BaseFluxVariables) -{ - typedef typename GET_PROP_TYPE(TypeTag, BaseFluxVariables) BaseFluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel) EffectiveDiffusivityModel; - - enum { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld, - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents) - }; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - - typedef Dune::FieldVector<Scalar, dim> DimVector; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - gPhaseIdx = Indices::gPhaseIdx, - - wCompIdx = Indices::wCompIdx, - nCompIdx = Indices::nCompIdx, - gCompIdx = Indices::gCompIdx - }; - -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 Evaluate flux at inner sub-control-volume face or on a boundary face - */ - ThreePThreeCFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int fIdx, - const ElementVolumeVariables &elemVolVars, - const bool onBoundary = false) - : BaseFluxVariables(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) - { - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - density_[phaseIdx] = Scalar(0); - molarDensity_[phaseIdx] = Scalar(0); - massFractionCompWGrad_[phaseIdx] = Scalar(0); - massFractionCompNGrad_[phaseIdx] = Scalar(0); - massFractionCompGGrad_[phaseIdx] = Scalar(0); - moleFractionCompWGrad_[phaseIdx] = Scalar(0); - moleFractionCompNGrad_[phaseIdx] = Scalar(0); - moleFractionCompGGrad_[phaseIdx] = Scalar(0); - } - - calculateGradients_(problem, element, elemVolVars); - calculatePorousDiffCoeff_(problem, element, elemVolVars); - }; - -private: - void calculateGradients_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - // calculate gradients - GlobalPosition tmp(0.0); - for (unsigned int idx = 0; - idx < this->face().numFap; - idx++) // loop over adjacent vertices - { - // FE gradient at vertex idx - const GlobalPosition &feGrad = this->face().grad[idx]; - - // index for the element volume variables - int volVarsIdx = this->face().fapIndices[idx]; - - // the concentration gradient of the components - // component in the phases - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(wPhaseIdx, wCompIdx); - massFractionCompWGrad_[wPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(nPhaseIdx, wCompIdx); - massFractionCompWGrad_[nPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(gPhaseIdx, wCompIdx); - massFractionCompWGrad_[gPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(wPhaseIdx, nCompIdx); - massFractionCompNGrad_[wPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(nPhaseIdx, nCompIdx); - massFractionCompNGrad_[nPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(gPhaseIdx, nCompIdx); - massFractionCompNGrad_[gPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(wPhaseIdx, gCompIdx); - massFractionCompGGrad_[wPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(nPhaseIdx, gCompIdx); - massFractionCompGGrad_[nPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].massFraction(gPhaseIdx, gCompIdx); - massFractionCompGGrad_[gPhaseIdx] += tmp; - - // the molar concentration gradients of the components - // in the phases - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, wCompIdx); - moleFractionCompWGrad_[wPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, wCompIdx); - moleFractionCompWGrad_[nPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(gPhaseIdx, wCompIdx); - moleFractionCompWGrad_[gPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, nCompIdx); - moleFractionCompNGrad_[wPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, nCompIdx); - moleFractionCompNGrad_[nPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(gPhaseIdx, nCompIdx); - moleFractionCompNGrad_[gPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, gCompIdx); - moleFractionCompGGrad_[wPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, gCompIdx); - moleFractionCompGGrad_[nPhaseIdx] += tmp; - - tmp = feGrad; - tmp *= elemVolVars[volVarsIdx].moleFraction(gPhaseIdx, gCompIdx); - moleFractionCompGGrad_[gPhaseIdx] += tmp; - } - } - - Scalar rhoFactor_(int phaseIdx, int scvIdx, const ElementVolumeVariables &elemVolVars) - { - static const Scalar eps = 1e-2; - const Scalar sat = elemVolVars[scvIdx].density(phaseIdx); - if (sat > eps) - return 0.5; - if (sat <= 0) - return 0; - - static const Dumux::Spline<Scalar> sp(0, eps, // x0, x1 - 0, 0.5, // y0, y1 - 0, 0); // m0, m1 - return sp.eval(sat); - } - - void calculatePorousDiffCoeff_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) - { - - const VolumeVariables &volVarsI = elemVolVars[this->face().i]; - const VolumeVariables &volVarsJ = elemVolVars[this->face().j]; - - Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficientMatrix_i = volVarsI.diffusionCoefficient(); - Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficientMatrix_j = volVarsJ.diffusionCoefficient(); - - // the effective diffusion coefficients at vertex i and j - Scalar diffCoeffI; - Scalar diffCoeffJ; - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - // make sure to calculate only diffusion coefficents - // for phases which exist in both finite volumes - /* \todo take care: This should be discussed once again - * as long as a meaningful value can be found for the required mole fraction - * diffusion should work even without this one here */ - if (volVarsI.saturation(phaseIdx) <= 0 || - volVarsJ.saturation(phaseIdx) <= 0) - { - porousDiffCoeff_[phaseIdx][wCompIdx] = 0.0; - porousDiffCoeff_[phaseIdx][nCompIdx] = 0.0; - porousDiffCoeff_[phaseIdx][gCompIdx] = 0.0; - continue; - } - - // Diffusion coefficient in the porous medium - diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), - volVarsI.saturation(phaseIdx), - diffusionCoefficientMatrix_i[phaseIdx][wCompIdx]); - diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), - volVarsJ.saturation(phaseIdx), - diffusionCoefficientMatrix_j[phaseIdx][wCompIdx]); - - // -> harmonic mean - porousDiffCoeff_[phaseIdx][wCompIdx] = harmonicMean(diffCoeffI, diffCoeffJ); - - // Diffusion coefficient in the porous medium - diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), - volVarsI.saturation(phaseIdx), - diffusionCoefficientMatrix_i[phaseIdx][nCompIdx]); - diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), - volVarsJ.saturation(phaseIdx), - diffusionCoefficientMatrix_j[phaseIdx][nCompIdx]); - - // -> harmonic mean - porousDiffCoeff_[phaseIdx][nCompIdx] = harmonicMean(diffCoeffI, diffCoeffJ); - - // Diffusion coefficient in the porous medium - diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), - volVarsI.saturation(phaseIdx), - diffusionCoefficientMatrix_i[phaseIdx][gCompIdx]); - diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), - volVarsJ.saturation(phaseIdx), - diffusionCoefficientMatrix_j[phaseIdx][gCompIdx]); - - // -> harmonic mean - porousDiffCoeff_[phaseIdx][gCompIdx] = harmonicMean(diffCoeffI, diffCoeffJ); - } - } - -public: - /*! - * \brief The diffusivity matrix - * - * \tparam Scalar Field type - * \tparam numPhases The number of phases of the problem - * \tparam numComponents The number of components of the problem - */ - Dune::FieldMatrix<Scalar, numPhases, numComponents> porousDiffCoeff() const - { return porousDiffCoeff_; }; - - /*! - * \brief Return density \f$\mathrm{[kg/m^3]}\f$ of a phase. - * - * \param phaseIdx The phase index - */ - Scalar density(int phaseIdx) const - { return density_[phaseIdx]; } - - /*! - * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ of a phase. - * - * \param phaseIdx The phase index - */ - Scalar molarDensity(int phaseIdx) const - { return molarDensity_[phaseIdx]; } - - /*! - * \brief The mass fraction gradient of the water in a phase. - * - * \param phaseIdx The phase index - */ - const GlobalPosition &massFractionCompWGrad(int phaseIdx) const - {return massFractionCompWGrad_[phaseIdx];} - - /*! - * \brief The mass fraction gradient of the contaminant in a phase. - * - * \param phaseIdx The phase index - */ - const GlobalPosition &massFractionCompNGrad(int phaseIdx) const - { return massFractionCompNGrad_[phaseIdx]; }; - - /*! - * \brief The mass fraction gradient of gas in a phase. - * - * \param phaseIdx The phase index - */ - const GlobalPosition &massFractionCompGGrad(int phaseIdx) const - { return massFractionCompGGrad_[phaseIdx]; }; - - /*! - * \brief The mole fraction gradient of the water in a phase. - * - * \param phaseIdx The phase index - */ - const GlobalPosition &moleFractionCompWGrad(int phaseIdx) const - { return moleFractionCompWGrad_[phaseIdx]; }; - - /*! - * \brief The mole fraction gradient of the contaminant in a phase. - * - * \param phaseIdx The phase index - */ - const GlobalPosition &moleFractionCompNGrad(int phaseIdx) const - { return moleFractionCompNGrad_[phaseIdx]; }; - - /*! - * \brief The mole fraction gradient of gas in a phase. - * - * \param phaseIdx The phase index - */ - const GlobalPosition &moleFractionCompGGrad(int phaseIdx) const - { return moleFractionCompGGrad_[phaseIdx]; }; - -protected: - // gradients - GlobalPosition massFractionCompWGrad_[numPhases]; - GlobalPosition massFractionCompNGrad_[numPhases]; - GlobalPosition massFractionCompGGrad_[numPhases]; - GlobalPosition moleFractionCompWGrad_[numPhases]; - GlobalPosition moleFractionCompNGrad_[numPhases]; - GlobalPosition moleFractionCompGGrad_[numPhases]; - - // density of each face at the integration point - Scalar density_[numPhases], molarDensity_[numPhases]; - - // the diffusivity matrix for the porous medium - Dune::FieldMatrix<Scalar, numPhases, numComponents> porousDiffCoeff_; -}; - -} // end namespace +#include <dumux/porousmediumflow/3p3c/implicit/fluxvariables.hh> #endif diff --git a/dumux/implicit/3p3c/3p3cindices.hh b/dumux/implicit/3p3c/3p3cindices.hh index e203747f7c..74f9ed7cd8 100644 --- a/dumux/implicit/3p3c/3p3cindices.hh +++ b/dumux/implicit/3p3c/3p3cindices.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 indices required for the three-phase three-component - * fully implicit model. - */ -#ifndef DUMUX_3P3C_INDICES_HH -#define DUMUX_3P3C_INDICES_HH +#ifndef DUMUX_3P3C_INDICES_HH_OLD +#define DUMUX_3P3C_INDICES_HH_OLD -#include "3p3cproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/indices.hh instead -namespace Dumux -{ - -/*! - * \ingroup ThreePThreeCModel - * \ingroup ImplicitIndices - * \brief The indices for the isothermal three-phase three-component model. - * - * \tparam formulation The formulation, only pgSwSn is available. - * \tparam PVOffset The first index in a primary variable vector. - */ -template <class TypeTag, int PVOffset = 0> -class ThreePThreeCIndices -{ - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - -public: - // Phase indices - static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< index of the wetting liquid phase - static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< index of the nonwetting liquid phase - static const int gPhaseIdx = FluidSystem::gPhaseIdx; //!< index of the gas phase - - // Component indices to indicate the main component - // of the corresponding phase at atmospheric pressure 1 bar - // and room temperature 20°C: - static const int wCompIdx = FluidSystem::wCompIdx; - static const int nCompIdx = FluidSystem::nCompIdx; - static const int gCompIdx = FluidSystem::gCompIdx; - - // present phases (-> 'pseudo' primary variable) - static const int threePhases = 1; //!< All three phases are present - static const int wPhaseOnly = 2; //!< Only the water phase is present - static const int gnPhaseOnly = 3; //!< Only gas and NAPL phases are present - static const int wnPhaseOnly = 4; //!< Only water and NAPL phases are present - static const int gPhaseOnly = 5; //!< Only gas phase is present - static const int wgPhaseOnly = 6; //!< Only water and gas phases are present - - // Primary variable indices - static const int pressureIdx = PVOffset + 0; //!< Index for gas phase pressure in a solution vector - static const int switch1Idx = PVOffset + 1; //!< Index 1 of saturation or mole fraction - static const int switch2Idx = PVOffset + 2; //!< Index 2 of saturation or mole fraction - - //! Index for gas phase pressure in a solution vector - static const int pgIdx = pressureIdx; - //! Index of either the saturation of the wetting phase or the mole fraction secondary component if a phase is not present - static const int sOrX1Idx = switch1Idx; - //! Index of either the saturation of the nonwetting phase or the mole fraction secondary component if a phase is not present - static const int sOrX2Idx = switch2Idx; - - // equation indices - static const int conti0EqIdx = PVOffset + wCompIdx; //!< Index of the mass conservation equation for the water component - static const int conti1EqIdx = conti0EqIdx + nCompIdx; //!< Index of the mass conservation equation for the contaminant component - static const int conti2EqIdx = conti0EqIdx + gCompIdx; //!< Index of the mass conservation equation for the gas component - - static const int contiWEqIdx = conti0EqIdx + wCompIdx; //!< index of the mass conservation equation for the water component - static const int contiNEqIdx = conti0EqIdx + nCompIdx; //!< index of the mass conservation equation for the contaminant component - static const int contiGEqIdx = conti0EqIdx + gCompIdx; //!< index of the mass conservation equation for the air component -}; - -} +#include <dumux/porousmediumflow/3p3c/implicit/indices.hh> #endif diff --git a/dumux/implicit/3p3c/3p3clocalresidual.hh b/dumux/implicit/3p3c/3p3clocalresidual.hh index e1abefc1e8..29a4ac9e7f 100644 --- a/dumux/implicit/3p3c/3p3clocalresidual.hh +++ b/dumux/implicit/3p3c/3p3clocalresidual.hh @@ -1,238 +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 Jacobian matrix for problems - * using the three-phase three-component fully implicit model. - */ -#ifndef DUMUX_3P3C_LOCAL_RESIDUAL_HH -#define DUMUX_3P3C_LOCAL_RESIDUAL_HH +#ifndef DUMUX_3P3C_LOCAL_RESIDUAL_HH_OLD +#define DUMUX_3P3C_LOCAL_RESIDUAL_HH_OLD -#include "3p3cproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/localresidual.hh instead -namespace Dumux -{ -/*! - * \ingroup ThreePThreeCModel - * \ingroup ImplicitLocalResidual - * \brief Element-wise calculation of the Jacobian matrix for problems - * using the three-phase three-component fully implicit model. - * - * This class is used to fill the gaps in BoxLocalResidual for the 3P3C flow. - */ -template<class TypeTag> -class ThreePThreeCLocalResidual: 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, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum { - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - - conti0EqIdx = Indices::conti0EqIdx,//!< Index of the mass conservation equation for the water component - conti1EqIdx = Indices::conti1EqIdx,//!< Index of the mass conservation equation for the contaminant component - conti2EqIdx = Indices::conti2EqIdx,//!< Index of the mass conservation equation for the gas component - - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - gPhaseIdx = Indices::gPhaseIdx, - - wCompIdx = Indices::wCompIdx, - nCompIdx = Indices::nCompIdx, - gCompIdx = Indices::gCompIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - -public: - /*! - * \brief Evaluate the amount of all conservation quantities - * (e.g. phase mass) within a sub-control volume. - * - * The result should be averaged over the volume (e.g. phase mass - * inside a sub control volume divided by the volume) - * - * \param storage The mass of the component 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, const 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]; - - // compute storage term of all components within all phases - storage = 0; - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - storage[conti0EqIdx + compIdx] += - volVars.porosity() - * volVars.saturation(phaseIdx) - * volVars.molarDensity(phaseIdx) - * volVars.moleFraction(phaseIdx, compIdx); - } - } - } - - /*! - * \brief Evaluates the total flux of all conservation quantities - * 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 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, const int fIdx, const bool onBoundary=false) const - { - FluxVariables fluxVars(this->problem_(), - this->element_(), - this->fvGeometry_(), - fIdx, - this->curVolVars_(), - onBoundary); - - flux = 0; - asImp_()->computeAdvectiveFlux(flux, fluxVars); - asImp_()->computeDiffusiveFlux(flux, fluxVars); - } - - /*! - * \brief Evaluates the advective mass flux of all components 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 - { - Scalar massUpwindWeight = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); - - //////// - // advective fluxes of all components in all phases - //////// - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - // 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)); - - for (int compIdx = 0; compIdx < numComponents; ++compIdx) - { - // add advective flux of current component in current - // phase - // if alpha > 0 and alpha < 1 then both upstream and downstream - // nodes need their contribution - // if alpha == 1 (which is mostly the case) then, the downstream - // node is not evaluated - int eqIdx = conti0EqIdx + compIdx; - flux[eqIdx] += fluxVars.volumeFlux(phaseIdx) - * (massUpwindWeight - * up.molarDensity(phaseIdx) - * up.moleFraction(phaseIdx, compIdx) - + - (1.0 - massUpwindWeight) - * dn.molarDensity(phaseIdx) - * dn.moleFraction(phaseIdx, compIdx)); - } - } - } - - /*! - * \brief Adds the diffusive mass flux of all components over - * a face of a subcontrol volume. - * - * \param flux The diffusive flux over the sub-control-volume face for each component - * \param fluxVars The flux variables at the current SCV - */ - - void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const - { - // TODO: reference!? Dune::FieldMatrix<Scalar, numPhases, numComponents> averagedPorousDiffCoeffMatrix = fluxVars.porousDiffCoeff(); - // add diffusive flux of gas component in liquid phase - Scalar tmp = - fluxVars.porousDiffCoeff()[wPhaseIdx][gCompIdx] * fluxVars.molarDensity(wPhaseIdx); - tmp *= (fluxVars.moleFractionCompGGrad(wPhaseIdx) * fluxVars.face().normal); - Scalar jGW = tmp; - - tmp = - fluxVars.porousDiffCoeff()[wPhaseIdx][nCompIdx] * fluxVars.molarDensity(wPhaseIdx); - tmp *= (fluxVars.moleFractionCompNGrad(wPhaseIdx) * fluxVars.face().normal); - Scalar jNW = tmp; - - Scalar jWW = -(jGW+jNW); - - tmp = - fluxVars.porousDiffCoeff()[gPhaseIdx][wCompIdx] * fluxVars.molarDensity(gPhaseIdx); - tmp *= (fluxVars.moleFractionCompWGrad(gPhaseIdx) * fluxVars.face().normal); - Scalar jWG = tmp; - - tmp = - fluxVars.porousDiffCoeff()[gPhaseIdx][nCompIdx] * fluxVars.molarDensity(gPhaseIdx); - tmp *= (fluxVars.moleFractionCompNGrad(gPhaseIdx) * fluxVars.face().normal); - Scalar jNG = tmp; - - Scalar jGG = -(jWG+jNG); - - tmp = - fluxVars.porousDiffCoeff()[nPhaseIdx][wCompIdx] * fluxVars.molarDensity(nPhaseIdx); - tmp *= (fluxVars.moleFractionCompWGrad(nPhaseIdx) * fluxVars.face().normal); - Scalar jWN = tmp; - - tmp = - fluxVars.porousDiffCoeff()[nPhaseIdx][gCompIdx] * fluxVars.molarDensity(nPhaseIdx); - tmp *= (fluxVars.moleFractionCompGGrad(nPhaseIdx) * fluxVars.face().normal); - Scalar jGN = tmp; - - Scalar jNN = -(jGN+jWN); - - flux[conti0EqIdx] += jWW+jWG+jWN; - flux[conti1EqIdx] += jNW+jNG+jNN; - flux[conti2EqIdx] += jGW+jGG+jGN; - } - -protected: - Implementation *asImp_() - { - return static_cast<Implementation *> (this); - } - - const Implementation *asImp_() const - { - return static_cast<const Implementation *> (this); - } -}; - -} // end namespace +#include <dumux/porousmediumflow/3p3c/implicit/localresidual.hh> #endif diff --git a/dumux/implicit/3p3c/3p3cmodel.hh b/dumux/implicit/3p3c/3p3cmodel.hh index dacdf5d80b..faaca36f3a 100644 --- a/dumux/implicit/3p3c/3p3cmodel.hh +++ b/dumux/implicit/3p3c/3p3cmodel.hh @@ -1,1020 +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 Adaption of the fully implicit scheme to the three-phase three-component - * flow model. - * - * The model is designed for simulating three fluid phases with water, gas, and - * a liquid contaminant (NAPL - non-aqueous phase liquid) - */ -#ifndef DUMUX_3P3C_MODEL_HH -#define DUMUX_3P3C_MODEL_HH +#ifndef DUMUX_3P3C_MODEL_HH_OLD +#define DUMUX_3P3C_MODEL_HH_OLD -#include <dumux/porousmediumflow/implicit/velocityoutput.hh> -#include "3p3cproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/model.hh instead -namespace Dumux -{ -/*! - * \ingroup ThreePThreeCModel - * \brief Adaption of the fully implicit scheme to the three-phase three-component - * flow model. - * - * This model implements three-phase three-component flow of three fluid phases - * \f$\alpha \in \{ water, gas, NAPL \}\f$ each composed of up to three components - * \f$\kappa \in \{ water, air, contaminant \}\f$. The standard multiphase Darcy - * approach is used as the equation for the conservation of momentum: - * \f[ - v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mathbf{K} - \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) - * \f] - * - * By inserting this into the equations for the conservation of the - * components, one transport equation for each component is obtained as - * \f{eqnarray*} - && \phi \frac{\partial (\sum_\alpha \varrho_{\alpha,mol} x_\alpha^\kappa - S_\alpha )}{\partial t} - - \sum\limits_\alpha \text{div} \left\{ \frac{k_{r\alpha}}{\mu_\alpha} - \varrho_{\alpha,mol} x_\alpha^\kappa \mathbf{K} - (\textbf{grad}\, p_\alpha - \varrho_{\alpha,mass} \mbox{\bf g}) \right\} - \nonumber \\ - \nonumber \\ - && - \sum\limits_\alpha \text{div} \left\{ D_\text{pm}^\kappa \varrho_{\alpha,mol} - \textbf{grad} x^\kappa_{\alpha} \right\} - - q^\kappa = 0 \qquad \forall \kappa , \; \forall \alpha - \f} - * - * Note that these balance equations are molar. - * - * 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 model uses commonly applied auxiliary conditions like - * \f$S_w + S_n + S_g = 1\f$ for the saturations and - * \f$x^w_\alpha + x^a_\alpha + x^c_\alpha = 1\f$ for the mole fractions. - * Furthermore, the phase pressures are related to each other via - * capillary pressures between the fluid phases, which are functions of - * the saturation, e.g. according to the approach of Parker et al. - * - * The used primary variables are dependent on the locally present fluid phases. - * An adaptive primary variable switch is included. The phase state is stored for all nodes - * of the system. The following cases can be distinguished: - * <ul> - * <li> All three phases are present: Primary variables are two saturations \f$(S_w\f$ and \f$S_n)\f$, - * and a pressure, in this case \f$p_g\f$. </li> - * <li> Only the water phase is present: Primary variables are now the mole fractions of air and - * contaminant in the water phase \f$(x_w^a\f$ and \f$x_w^c)\f$, as well as the gas pressure, which is, - * of course, in a case where only the water phase is present, just the same as the water pressure. </li> - * <li> Gas and NAPL phases are present: Primary variables \f$(S_n\f$, \f$x_g^w\f$, \f$p_g)\f$. </li> - * <li> Water and NAPL phases are present: Primary variables \f$(S_n\f$, \f$x_w^a\f$, \f$p_g)\f$. </li> - * <li> Only gas phase is present: Primary variables \f$(x_g^w\f$, \f$x_g^c\f$, \f$p_g)\f$. </li> - * <li> Water and gas phases are present: Primary variables \f$(S_w\f$, \f$x_w^g\f$, \f$p_g)\f$. </li> - * </ul> - */ -template<class TypeTag> -class ThreePThreeCModel: public GET_PROP_TYPE(TypeTag, BaseModel) -{ - typedef typename GET_PROP_TYPE(TypeTag, BaseModel) ParentType; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - - enum { - dim = GridView::dimension, - dimWorld = GridView::dimensionworld, - - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - - switch1Idx = Indices::switch1Idx, - switch2Idx = Indices::switch2Idx, - - - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - gPhaseIdx = Indices::gPhaseIdx, - - wCompIdx = Indices::wCompIdx, - nCompIdx = Indices::nCompIdx, - gCompIdx = Indices::gCompIdx, - - threePhases = Indices::threePhases, - wPhaseOnly = Indices::wPhaseOnly, - gnPhaseOnly = Indices::gnPhaseOnly, - wnPhaseOnly = Indices::wnPhaseOnly, - gPhaseOnly = Indices::gPhaseOnly, - wgPhaseOnly = Indices::wgPhaseOnly - - }; - - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - -public: - /*! - * \brief Initialize the static data with the initial solution. - * - * \param problem The problem to be solved - */ - void init(Problem &problem) - { - ParentType::init(problem); - - staticDat_.resize(this->numDofs()); - - setSwitched_(false); - - if (isBox) - { - for (const auto& vertex : Dune::vertices(this->gridView_())) - { - int vIdxGlobal = this->dofMapper().index(vertex); - - const GlobalPosition &globalPos = vertex.geometry().corner(0); - - // initialize phase presence - staticDat_[vIdxGlobal].phasePresence - = this->problem_().initialPhasePresence(vertex, vIdxGlobal, - globalPos); - staticDat_[vIdxGlobal].wasSwitched = false; - - staticDat_[vIdxGlobal].oldPhasePresence - = staticDat_[vIdxGlobal].phasePresence; - } - } - else - { - for (const auto& element : Dune::elements(this->gridView_())) - { - int eIdxGlobal = this->dofMapper().index(element); - const GlobalPosition &globalPos = element.geometry().center(); - - // initialize phase presence - staticDat_[eIdxGlobal].phasePresence - = this->problem_().initialPhasePresence(*this->gridView_().template begin<dim> (), - eIdxGlobal, globalPos); - staticDat_[eIdxGlobal].wasSwitched = false; - - staticDat_[eIdxGlobal].oldPhasePresence - = staticDat_[eIdxGlobal].phasePresence; - } - } - } - - /*! - * \brief Compute the total storage inside one phase of all - * conservation quantities. - * - * \param storage Contains the storage of each component for one phase - * \param phaseIdx The phase index - */ - void globalPhaseStorage(PrimaryVariables &storage, const int phaseIdx) - { - storage = 0; - - for (const auto& element : Dune::elements(this->gridView_())) { - if(element.partitionType() == Dune::InteriorEntity) - { - this->localResidual().evalPhaseStorage(element, phaseIdx); - - for (unsigned int i = 0; i < this->localResidual().storageTerm().size(); ++i) - storage += this->localResidual().storageTerm()[i]; - } - } - if (this->gridView_().comm().size() > 1) - storage = this->gridView_().comm().sum(storage); - } - - - /*! - * \brief Called by the update() method if applying the newton - * method was unsuccessful. - */ - void updateFailed() - { - ParentType::updateFailed(); - - setSwitched_(false); - resetPhasePresence_(); - }; - - /*! - * \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() - { - ParentType::advanceTimeLevel(); - - // update the phase state - updateOldPhasePresence_(); - setSwitched_(false); - } - - /*! - * \brief Return true if the primary variables were switched for - * at least one vertex after the last timestep. - */ - bool switched() const - { - return switchFlag_; - } - - /*! - * \brief Returns the phase presence of the current or the old solution of a degree of freedom. - * - * \param dofIdxGlobal The global index of the degree of freedom - * \param oldSol Evaluate function with solution of current or previous time step - */ - int phasePresence(int dofIdxGlobal, bool oldSol) const - { - return - oldSol - ? staticDat_[dofIdxGlobal].oldPhasePresence - : staticDat_[dofIdxGlobal].phasePresence; - } - - /*! - * \brief Append all quantities of interest which can be derived - * from the solution of the current time step to the VTK - * writer. - * - * \param sol The solution vector - * \param writer The writer for multi-file VTK datasets - */ - template<class MultiWriter> - void addOutputVtkFields(const SolutionVector &sol, - MultiWriter &writer) - { - typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; - typedef Dune::BlockVector<Dune::FieldVector<double, dimWorld> > VectorField; - - // get the number of degrees of freedom - unsigned numDofs = this->numDofs(); - - // create the required scalar fields - ScalarField *saturation[numPhases]; - ScalarField *pressure[numPhases]; - ScalarField *density[numPhases]; - - for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { - saturation[phaseIdx] = writer.allocateManagedBuffer(numDofs); - pressure[phaseIdx] = writer.allocateManagedBuffer(numDofs); - density[phaseIdx] = writer.allocateManagedBuffer(numDofs); - } - - ScalarField *phasePresence = writer.allocateManagedBuffer (numDofs); - ScalarField *moleFraction[numPhases][numComponents]; - for (int i = 0; i < numPhases; ++i) - for (int j = 0; j < numComponents; ++j) - moleFraction[i][j] = writer.allocateManagedBuffer (numDofs); - ScalarField *temperature = writer.allocateManagedBuffer (numDofs); - ScalarField *poro = writer.allocateManagedBuffer(numDofs); - VectorField *velocityN = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); - VectorField *velocityW = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); - VectorField *velocityG = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); - ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - // initialize velocity fields - for (unsigned int i = 0; i < numDofs; ++i) - { - (*velocityN)[i] = Scalar(0); - (*velocityW)[i] = Scalar(0); - (*velocityG)[i] = Scalar(0); - } - } - - unsigned numElements = this->gridView_().size(0); - ScalarField *rank = writer.allocateManagedBuffer (numElements); - - for (const auto& element : Dune::elements(this->gridView_())) - { - if(element.partitionType() == Dune::InteriorEntity) - { - int eIdx = this->problem_().elementMapper().index(element); - (*rank)[eIdx] = this->gridView_().comm().rank(); - - FVElementGeometry fvGeometry; - fvGeometry.update(this->gridView_(), element); - - - ElementVolumeVariables elemVolVars; - elemVolVars.update(this->problem_(), - element, - fvGeometry, - false /* oldSol? */); - - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); - - for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { - (*saturation[phaseIdx])[dofIdxGlobal] = elemVolVars[scvIdx].saturation(phaseIdx); - (*pressure[phaseIdx])[dofIdxGlobal] = elemVolVars[scvIdx].pressure(phaseIdx); - (*density[phaseIdx])[dofIdxGlobal] = elemVolVars[scvIdx].density(phaseIdx); - } - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - for (int compIdx = 0; compIdx < numComponents; ++compIdx) { - (*moleFraction[phaseIdx][compIdx])[dofIdxGlobal] = - elemVolVars[scvIdx].moleFraction(phaseIdx, - compIdx); - - Valgrind::CheckDefined((*moleFraction[phaseIdx][compIdx])[dofIdxGlobal]); - } - } - - (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity(); - (*temperature)[dofIdxGlobal] = elemVolVars[scvIdx].temperature(); - (*phasePresence)[dofIdxGlobal] = staticDat_[dofIdxGlobal].phasePresence; - } - - // velocity output - velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); - velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); - velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, gPhaseIdx); - } - } - - writer.attachDofData(*saturation[wPhaseIdx], "Sw", isBox); - writer.attachDofData(*saturation[nPhaseIdx], "Sn", isBox); - writer.attachDofData(*saturation[gPhaseIdx], "Sg", isBox); - writer.attachDofData(*pressure[wPhaseIdx], "pw", isBox); - writer.attachDofData(*pressure[nPhaseIdx], "pn", isBox); - writer.attachDofData(*pressure[gPhaseIdx], "pg", isBox); - writer.attachDofData(*density[wPhaseIdx], "rhow", isBox); - writer.attachDofData(*density[nPhaseIdx], "rhon", isBox); - writer.attachDofData(*density[gPhaseIdx], "rhog", isBox); - - for (int i = 0; i < numPhases; ++i) - { - for (int j = 0; j < numComponents; ++j) - { - std::ostringstream oss; - oss << "x^" - << FluidSystem::componentName(j) - << "_" - << FluidSystem::phaseName(i); - writer.attachDofData(*moleFraction[i][j], oss.str().c_str(), isBox); - } - } - writer.attachDofData(*poro, "porosity", isBox); - writer.attachDofData(*temperature, "temperature", isBox); - writer.attachDofData(*phasePresence, "phase presence", isBox); - - if (velocityOutput.enableOutput()) // check if velocity output is demanded - { - writer.attachDofData(*velocityW, "velocityW", isBox, dim); - writer.attachDofData(*velocityN, "velocityN", isBox, dim); - writer.attachDofData(*velocityG, "velocityG", isBox, dim); - } - - writer.attachCellData(*rank, "process rank"); - } - - /*! - * \brief Write the current solution to a restart file. - * - * \param outStream The output stream of one entity for the restart file - * \param entity The entity, either a vertex or an element - */ - template<class Entity> - void serializeEntity(std::ostream &outStream, const Entity &entity) - { - // write primary variables - ParentType::serializeEntity(outStream, entity); - - int dofIdxGlobal = this->dofMapper().index(entity); - - if (!outStream.good()) - DUNE_THROW(Dune::IOError, "Could not serialize entity " << dofIdxGlobal); - - outStream << staticDat_[dofIdxGlobal].phasePresence << " "; - } - - /*! - * \brief Reads the current solution from a restart file. - * - * \param inStream The input stream of one entity from the restart file - * \param entity The entity, either a vertex or an element - */ - template<class Entity> - void deserializeEntity(std::istream &inStream, const Entity &entity) - { - // read primary variables - ParentType::deserializeEntity(inStream, entity); - - // read phase presence - int dofIdxGlobal = this->dofMapper().index(entity); - - if (!inStream.good()) - DUNE_THROW(Dune::IOError, - "Could not deserialize entity " << dofIdxGlobal); - - inStream >> staticDat_[dofIdxGlobal].phasePresence; - staticDat_[dofIdxGlobal].oldPhasePresence - = staticDat_[dofIdxGlobal].phasePresence; - - } - - /*! - * \brief Update the static data of all vertices in the grid. - * - * \param curGlobalSol The current global solution - * \param oldGlobalSol The previous global solution - */ - void updateStaticData(SolutionVector &curGlobalSol, - const SolutionVector &oldGlobalSol) - { - bool wasSwitched = false; - int succeeded; - try { - - for (unsigned i = 0; i < staticDat_.size(); ++i) - staticDat_[i].visited = false; - - FVElementGeometry fvGeometry; - static VolumeVariables volVars; - for (const auto& element : Dune::elements(this->gridView_())) - { - fvGeometry.update(this->gridView_(), element); - for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) - { - int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); - - if (staticDat_[dofIdxGlobal].visited) - continue; - - staticDat_[dofIdxGlobal].visited = true; - volVars.update(curGlobalSol[dofIdxGlobal], - this->problem_(), - element, - fvGeometry, - scvIdx, - false); - const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (primaryVarSwitch_(curGlobalSol, - volVars, - dofIdxGlobal, - globalPos)) - { - this->jacobianAssembler().markDofRed(dofIdxGlobal); - wasSwitched = true; - } - } - } - succeeded = 1; - } - catch (Dumux::NumericalProblem &e) - { - std::cout << "\n" - << "Rank " << this->problem_().gridView().comm().rank() - << " caught an exception while updating the static data." << e.what() - << "\n"; - succeeded = 0; - } - //make sure that all processes succeeded. If not throw a NumericalProblem to decrease the time step size. - if (this->gridView_().comm().size() > 1) - succeeded = this->gridView_().comm().min(succeeded); - - if (!succeeded) { - DUNE_THROW(NumericalProblem, - "A process did not succeed in updating the static data."); - return; - } - - // make sure that if there was a variable switch in an - // other partition we will also set the switch flag - // for our partition. - if (this->gridView_().comm().size() > 1) - wasSwitched = this->gridView_().comm().max(wasSwitched); - - setSwitched_(wasSwitched); - } - -protected: - /*! - * \brief Data which is attached to each vertex and is not only - * stored locally. - */ - struct StaticVars - { - int phasePresence; - bool wasSwitched; - - int oldPhasePresence; - bool visited; - }; - - /*! - * \brief Reset the current phase presence of all vertices to the old one. - * - * This is done after an update failed. - */ - void resetPhasePresence_() - { - for (unsigned int i = 0; i < this->numDofs(); ++i) - { - staticDat_[i].phasePresence - = staticDat_[i].oldPhasePresence; - staticDat_[i].wasSwitched = false; - } - } - - /*! - * \brief Set the old phase of all verts state to the current one. - */ - void updateOldPhasePresence_() - { - for (unsigned int i = 0; i < this->numDofs(); ++i) - { - staticDat_[i].oldPhasePresence - = staticDat_[i].phasePresence; - staticDat_[i].wasSwitched = false; - } - } - - /*! - * \brief Set whether there was a primary variable switch after in - * the last timestep. - */ - void setSwitched_(bool yesno) - { - switchFlag_ = yesno; - } - - // perform variable switch at a vertex; Returns true if a - // variable switch was performed. - bool primaryVarSwitch_(SolutionVector &globalSol, - const VolumeVariables &volVars, - int dofIdxGlobal, - const GlobalPosition &globalPos) - { - // evaluate primary variable switch - bool wouldSwitch = false; - int phasePresence = staticDat_[dofIdxGlobal].phasePresence; - int newPhasePresence = phasePresence; - - // check if a primary var switch is necessary - if (phasePresence == threePhases) - { - Scalar Smin = 0; - if (staticDat_[dofIdxGlobal].wasSwitched) - Smin = -0.01; - - if (volVars.saturation(gPhaseIdx) <= Smin) - { - wouldSwitch = true; - // gas phase disappears - std::cout << "Gas phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sg: " - << volVars.saturation(gPhaseIdx) << std::endl; - newPhasePresence = wnPhaseOnly; - - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(wPhaseIdx, gCompIdx); - } - else if (volVars.saturation(wPhaseIdx) <= Smin) - { - wouldSwitch = true; - // water phase disappears - std::cout << "Water phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sw: " - << volVars.saturation(wPhaseIdx) << std::endl; - newPhasePresence = gnPhaseOnly; - - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(gPhaseIdx, wCompIdx); - } - else if (volVars.saturation(nPhaseIdx) <= Smin) - { - wouldSwitch = true; - // NAPL phase disappears - std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sn: " - << volVars.saturation(nPhaseIdx) << std::endl; - newPhasePresence = wgPhaseOnly; - - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(gPhaseIdx, nCompIdx); - } - } - else if (phasePresence == wPhaseOnly) - { - bool gasFlag = 0; - bool nonwettingFlag = 0; - // calculate fractions of the partial pressures in the - // hypothetical gas phase - Scalar xwg = volVars.moleFraction(gPhaseIdx, wCompIdx); - Scalar xgg = volVars.moleFraction(gPhaseIdx, gCompIdx); - Scalar xng = volVars.moleFraction(gPhaseIdx, nCompIdx); - /* take care: - for xgg in case wPhaseOnly we compute xgg=henry_air*x2w - for xwg in case wPhaseOnly we compute xwg=pwsat - for xng in case wPhaseOnly we compute xng=henry_NAPL*x1w - */ - - Scalar xgMax = 1.0; - if (xwg + xgg + xng > xgMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xgMax *= 1.02; - - // if the sum of the mole fractions would be larger than - // 100%, gas phase appears - if (xwg + xgg + xng > xgMax) - { - // gas phase appears - std::cout << "gas phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xwg + xgg + xng: " - << xwg + xgg + xng << std::endl; - gasFlag = 1; - } - - // calculate fractions in the hypothetical NAPL phase - Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); - /* take care: - for xnn in case wPhaseOnly we compute xnn=henry_mesitylene*x1w, - where a hypothetical gas pressure is assumed for the Henry - x0n is set to NULL (all NAPL phase is dirty) - x2n is set to NULL (all NAPL phase is dirty) - */ - - Scalar xnMax = 1.0; - if (xnn > xnMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xnMax *= 1.02; - - // if the sum of the hypothetical mole fractions would be larger than - // 100%, NAPL phase appears - if (xnn > xnMax) - { - // NAPL phase appears - std::cout << "NAPL phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xnn: " - << xnn << std::endl; - nonwettingFlag = 1; - } - - if ((gasFlag == 1) && (nonwettingFlag == 0)) - { - newPhasePresence = wgPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] = 0.9999; - globalSol[dofIdxGlobal][switch2Idx] = 0.0001; - } - else if ((gasFlag == 1) && (nonwettingFlag == 1)) - { - newPhasePresence = threePhases; - globalSol[dofIdxGlobal][switch1Idx] = 0.9999; - globalSol[dofIdxGlobal][switch2Idx] = 0.0001; - } - else if ((gasFlag == 0) && (nonwettingFlag == 1)) - { - newPhasePresence = wnPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(wPhaseIdx, gCompIdx); - globalSol[dofIdxGlobal][switch2Idx] = 0.0001; - } - } - else if (phasePresence == gnPhaseOnly) - { - bool nonwettingFlag = 0; - bool wettingFlag = 0; - - Scalar Smin = 0.0; - if (staticDat_[dofIdxGlobal].wasSwitched) - Smin = -0.01; - - if (volVars.saturation(nPhaseIdx) <= Smin) - { - wouldSwitch = true; - // NAPL phase disappears - std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sn: " - << volVars.saturation(nPhaseIdx) << std::endl; - nonwettingFlag = 1; - } - - - // calculate fractions of the hypothetical water phase - Scalar xww = volVars.moleFraction(wPhaseIdx, wCompIdx); - /* - take care:, xww, if no water is present, then take xww=xwg*pg/pwsat . - If this is larger than 1, then water appears - */ - Scalar xwMax = 1.0; - if (xww > xwMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xwMax *= 1.02; - - // if the sum of the mole fractions would be larger than - // 100%, gas phase appears - if (xww > xwMax) - { - // water phase appears - std::cout << "water phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : " - << xww << std::endl; - wettingFlag = 1; - } - - if ((wettingFlag == 1) && (nonwettingFlag == 0)) - { - newPhasePresence = threePhases; - globalSol[dofIdxGlobal][switch1Idx] = 0.0001; - globalSol[dofIdxGlobal][switch2Idx] = volVars.saturation(nPhaseIdx); - } - else if ((wettingFlag == 1) && (nonwettingFlag == 1)) - { - newPhasePresence = wgPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] = 0.0001; - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(gPhaseIdx, nCompIdx); - } - else if ((wettingFlag == 0) && (nonwettingFlag == 1)) - { - newPhasePresence = gPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(gPhaseIdx, wCompIdx); - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(gPhaseIdx, nCompIdx); - } - } - else if (phasePresence == wnPhaseOnly) - { - bool nonwettingFlag = 0; - bool gasFlag = 0; - - Scalar Smin = 0.0; - if (staticDat_[dofIdxGlobal].wasSwitched) - Smin = -0.01; - - if (volVars.saturation(nPhaseIdx) <= Smin) - { - wouldSwitch = true; - // NAPL phase disappears - std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sn: " - << volVars.saturation(nPhaseIdx) << std::endl; - nonwettingFlag = 1; - } - - // calculate fractions of the partial pressures in the - // hypothetical gas phase - Scalar xwg = volVars.moleFraction(gPhaseIdx, wCompIdx); - Scalar xgg = volVars.moleFraction(gPhaseIdx, gCompIdx); - Scalar xng = volVars.moleFraction(gPhaseIdx, nCompIdx); - /* take care: - for xgg in case wPhaseOnly we compute xgg=henry_air*x2w - for xwg in case wPhaseOnly we compute xwg=pwsat - for xng in case wPhaseOnly we compute xng=henry_NAPL*x1w - */ - Scalar xgMax = 1.0; - if (xwg + xgg + xng > xgMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xgMax *= 1.02; - - // if the sum of the mole fractions would be larger than - // 100%, gas phase appears - if (xwg + xgg + xng > xgMax) - { - // gas phase appears - std::cout << "gas phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xwg + xgg + xng: " - << xwg + xgg + xng << std::endl; - gasFlag = 1; - } - - if ((gasFlag == 1) && (nonwettingFlag == 0)) - { - newPhasePresence = threePhases; - globalSol[dofIdxGlobal][switch1Idx] = volVars.saturation(wPhaseIdx); - globalSol[dofIdxGlobal][switch2Idx] = volVars.saturation(nPhaseIdx); - } - else if ((gasFlag == 1) && (nonwettingFlag == 1)) - { - newPhasePresence = wgPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] = volVars.saturation(wPhaseIdx); - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(gPhaseIdx, nCompIdx); - } - else if ((gasFlag == 0) && (nonwettingFlag == 1)) - { - newPhasePresence = wPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(wPhaseIdx, gCompIdx); - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(wPhaseIdx, nCompIdx); - } - } - else if (phasePresence == gPhaseOnly) - { - bool nonwettingFlag = 0; - bool wettingFlag = 0; - - // calculate fractions in the hypothetical NAPL phase - Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); - /* - take care:, xnn, if no NAPL phase is there, take xnn=xng*pg/pcsat - if this is larger than 1, then NAPL appears - */ - - Scalar xnMax = 1.0; - if (xnn > xnMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xnMax *= 1.02; - - // if the sum of the hypothetical mole fraction would be larger than - // 100%, NAPL phase appears - if (xnn > xnMax) - { - // NAPL phase appears - std::cout << "NAPL phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xnn: " - << xnn << std::endl; - nonwettingFlag = 1; - } - // calculate fractions of the hypothetical water phase - Scalar xww = volVars.moleFraction(wPhaseIdx, wCompIdx); - /* - take care:, xww, if no water is present, then take xww=xwg*pg/pwsat . - If this is larger than 1, then water appears - */ - Scalar xwMax = 1.0; - if (xww > xwMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xwMax *= 1.02; - - // if the sum of the mole fractions would be larger than - // 100%, gas phase appears - if (xww > xwMax) - { - // water phase appears - std::cout << "water phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : " - << xww << std::endl; - wettingFlag = 1; - } - if ((wettingFlag == 1) && (nonwettingFlag == 0)) - { - newPhasePresence = wgPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] = 0.0001; - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(gPhaseIdx, nCompIdx); - } - else if ((wettingFlag == 1) && (nonwettingFlag == 1)) - { - newPhasePresence = threePhases; - globalSol[dofIdxGlobal][switch1Idx] = 0.0001; - globalSol[dofIdxGlobal][switch2Idx] = 0.0001; - } - else if ((wettingFlag == 0) && (nonwettingFlag == 1)) - { - newPhasePresence = gnPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(gPhaseIdx, wCompIdx); - globalSol[dofIdxGlobal][switch2Idx] = 0.0001; - } - } - else if (phasePresence == wgPhaseOnly) - { - bool nonwettingFlag = 0; - bool gasFlag = 0; - bool wettingFlag = 0; - - // get the fractions in the hypothetical NAPL phase - Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); - - // take care: if the NAPL phase is not present, take - // xnn=xng*pg/pcsat if this is larger than 1, then NAPL - // appears - Scalar xnMax = 1.0; - if (xnn > xnMax) - wouldSwitch = true; - if (staticDat_[dofIdxGlobal].wasSwitched) - xnMax *= 1.02; - - // if the sum of the hypothetical mole fraction would be larger than - // 100%, NAPL phase appears - if (xnn > xnMax) - { - // NAPL phase appears - std::cout << "NAPL phase appears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", xnn: " - << xnn << std::endl; - nonwettingFlag = 1; - } - - Scalar Smin = -1.e-6; - if (staticDat_[dofIdxGlobal].wasSwitched) - Smin = -0.01; - - if (volVars.saturation(gPhaseIdx) <= Smin) - { - wouldSwitch = true; - // gas phase disappears - std::cout << "Gas phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sg: " - << volVars.saturation(gPhaseIdx) << std::endl; - gasFlag = 1; - } - - Smin = 0.0; - if (staticDat_[dofIdxGlobal].wasSwitched) - Smin = -0.01; - - if (volVars.saturation(wPhaseIdx) <= Smin) - { - wouldSwitch = true; - // gas phase disappears - std::cout << "Water phase disappears at vertex " << dofIdxGlobal - << ", coordinates: " << globalPos << ", sw: " - << volVars.saturation(wPhaseIdx) << std::endl; - wettingFlag = 1; - } - - if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 1)) - { - newPhasePresence = gnPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(gPhaseIdx, wCompIdx); - globalSol[dofIdxGlobal][switch2Idx] = 0.0001; - } - else if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 0)) - { - newPhasePresence = threePhases; - globalSol[dofIdxGlobal][switch1Idx] = volVars.saturation(wPhaseIdx); - globalSol[dofIdxGlobal][switch2Idx] = 0.0; - } - else if ((gasFlag == 1) && (nonwettingFlag == 0) && (wettingFlag == 0)) - { - newPhasePresence = wPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(wPhaseIdx, gCompIdx); - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(wPhaseIdx, nCompIdx); - } - else if ((gasFlag == 0) && (nonwettingFlag == 0) && (wettingFlag == 1)) - { - newPhasePresence = gPhaseOnly; - globalSol[dofIdxGlobal][switch1Idx] - = volVars.moleFraction(gPhaseIdx, wCompIdx); - globalSol[dofIdxGlobal][switch2Idx] - = volVars.moleFraction(gPhaseIdx, nCompIdx); - } - } - - staticDat_[dofIdxGlobal].phasePresence = newPhasePresence; - staticDat_[dofIdxGlobal].wasSwitched = wouldSwitch; - return phasePresence != newPhasePresence; - } - - // parameters given in constructor - std::vector<StaticVars> staticDat_; - bool switchFlag_; -}; - -} - -#include "3p3cpropertydefaults.hh" +#include <dumux/porousmediumflow/3p3c/implicit/model.hh> #endif diff --git a/dumux/implicit/3p3c/3p3cnewtoncontroller.hh b/dumux/implicit/3p3c/3p3cnewtoncontroller.hh index 11ea75942e..06c9aa33fd 100644 --- a/dumux/implicit/3p3c/3p3cnewtoncontroller.hh +++ b/dumux/implicit/3p3c/3p3cnewtoncontroller.hh @@ -1,86 +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 A three-phase three-component 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_3P3C_NEWTON_CONTROLLER_HH -#define DUMUX_3P3C_NEWTON_CONTROLLER_HH +#ifndef DUMUX_3P3C_NEWTON_CONTROLLER_HH_OLD +#define DUMUX_3P3C_NEWTON_CONTROLLER_HH_OLD -#include "3p3cproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/newtoncontroller.hh instead -#include <dumux/nonlinear/newtoncontroller.hh> - -namespace Dumux { -/*! - * \ingroup Newton - * \ingroup ThreePThreeCModel - * \brief A three-phase three-component 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. - */ -template <class TypeTag> -class ThreePThreeCNewtonController : public NewtonController<TypeTag> -{ - typedef NewtonController<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - -public: - ThreePThreeCNewtonController(const Problem &problem) - : ParentType(problem) - {}; - - - /*! - * \brief Called after each Newton update - * - * \param uCurrentIter The current global solution vector - * \param uLastIter The previous global solution vector - */ - void newtonEndStep(SolutionVector &uCurrentIter, - const SolutionVector &uLastIter) - { - // call the method of the base class - this->method().model().updateStaticData(uCurrentIter, uLastIter); - ParentType::newtonEndStep(uCurrentIter, uLastIter); - } - - - /*! - * \brief Returns true if the current solution can be considered to - * be accurate enough - */ - bool newtonConverged() - { - if (this->method().model().switched()) - return false; - - return ParentType::newtonConverged(); - }; -}; -} +#include <dumux/porousmediumflow/3p3c/implicit/newtoncontroller.hh> #endif diff --git a/dumux/implicit/3p3c/3p3cproperties.hh b/dumux/implicit/3p3c/3p3cproperties.hh index 52a2762e8c..8dfef88f6e 100644 --- a/dumux/implicit/3p3c/3p3cproperties.hh +++ b/dumux/implicit/3p3c/3p3cproperties.hh @@ -1,82 +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 ThreePThreeCModel - */ -/*! - * \file - * - * \brief Defines the properties required for the three-phase three-component - * fully implicit model. - */ -#ifndef DUMUX_3P3C_PROPERTIES_HH -#define DUMUX_3P3C_PROPERTIES_HH +#ifndef DUMUX_3P3C_PROPERTIES_HH_OLD +#define DUMUX_3P3C_PROPERTIES_HH_OLD -#include <dumux/implicit/box/properties.hh> -#include <dumux/implicit/cellcentered/properties.hh> -#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/properties.hh instead - -namespace Dumux -{ - -namespace Properties -{ -////////////////////////////////////////////////////////////////// -// Type tags -////////////////////////////////////////////////////////////////// - -//! The type tags for the implicit three-phase three-component problems -NEW_TYPE_TAG(ThreePThreeC); -NEW_TYPE_TAG(BoxThreePThreeC, INHERITS_FROM(BoxModel, ThreePThreeC)); -NEW_TYPE_TAG(CCThreePThreeC, INHERITS_FROM(CCModel, ThreePThreeC)); - -//! The type tags for the corresponding non-isothermal problems -NEW_TYPE_TAG(ThreePThreeCNI, INHERITS_FROM(ThreePThreeC, NonIsothermal)); -NEW_TYPE_TAG(BoxThreePThreeCNI, INHERITS_FROM(BoxModel, ThreePThreeCNI)); -NEW_TYPE_TAG(CCThreePThreeCNI, INHERITS_FROM(CCModel, ThreePThreeCNI)); - -////////////////////////////////////////////////////////////////// -// Property tags -////////////////////////////////////////////////////////////////// - -NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system -NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system -NEW_PROP_TAG(Indices); //!< Enumerations for the model -NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters -NEW_PROP_TAG(FluidSystem); //!< Type of the multi-component relations -NEW_PROP_TAG(FluidState); //!< Type of the fluid state to be used - -NEW_PROP_TAG(MaterialLaw); //!< The material law which ought to be used (extracted from the spatial parameters) -NEW_PROP_TAG(MaterialLawParams); //!< The parameters of the material law (extracted from the spatial parameters) -NEW_PROP_TAG(EffectiveDiffusivityModel); //!< The employed model for the computation of the effective diffusivity - -NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem -NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The value of the upwind parameter for the mobility -NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation -NEW_PROP_TAG(UseConstraintSolver); //!< Determines whether a constraint solver should be used explicitly -NEW_PROP_TAG(BaseFluxVariables); //! The base flux variables -NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient -NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output -} -} +#include <dumux/porousmediumflow/3p3c/implicit/properties.hh> #endif diff --git a/dumux/implicit/3p3c/3p3cpropertydefaults.hh b/dumux/implicit/3p3c/3p3cpropertydefaults.hh index 187c15beed..26bfa705d8 100644 --- a/dumux/implicit/3p3c/3p3cpropertydefaults.hh +++ b/dumux/implicit/3p3c/3p3cpropertydefaults.hh @@ -1,211 +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 ThreePThreeCModel - * \file - * - * \brief Defines default values for most properties required by the - * three-phase three-component fully implicit model. - */ -#ifndef DUMUX_3P3C_PROPERTY_DEFAULTS_HH -#define DUMUX_3P3C_PROPERTY_DEFAULTS_HH +#ifndef DUMUX_3P3C_PROPERTY_DEFAULTS_HH_OLD +#define DUMUX_3P3C_PROPERTY_DEFAULTS_HH_OLD -#include "3p3cindices.hh" +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/propertydefaults.hh instead -#include "3p3cmodel.hh" -#include "3p3cindices.hh" -#include "3p3cfluxvariables.hh" -#include "3p3cvolumevariables.hh" -#include "3p3cproperties.hh" -#include "3p3cnewtoncontroller.hh" -#include "3p3clocalresidual.hh" - -#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> -#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> -#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> -#include <dumux/material/spatialparams/implicitspatialparams.hh> -#include <dumux/material/fluidmatrixinteractions/3p/thermalconductivitysomerton3p.hh> - -namespace Dumux -{ - -namespace Properties { -////////////////////////////////////////////////////////////////// -// Property values -////////////////////////////////////////////////////////////////// - -/*! - * \brief Set the property for the number of components. - * - * We just forward the number from the fluid system and use an static - * assert to make sure it is 3. - */ -SET_PROP(ThreePThreeC, NumComponents) -{ - private: - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - - public: - static const int value = FluidSystem::numComponents; - - static_assert(value == 3, - "Only fluid systems with 3 components are supported by the 3p3c model!"); -}; - -/*! - * \brief Set the property for the number of fluid phases. - * - * We just forward the number from the fluid system and use an static - * assert to make sure it is 3. - */ -SET_PROP(ThreePThreeC, NumPhases) -{ - private: - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - - public: - static const int value = FluidSystem::numPhases; - static_assert(value == 3, - "Only fluid systems with 3 phases are supported by the 3p3c model!"); -}; - -/*! - * \brief The fluid state which is used by the volume variables to - * store the thermodynamic state. This should be chosen - * appropriately for the model ((non-)isothermal, equilibrium, ...). - * This can be done in the problem. - */ -SET_PROP(ThreePThreeC, 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_INT_PROP(ThreePThreeC, NumEq, 3); //!< set the number of equations to 2 - -/*! - * \brief Set the property for the material parameters by extracting - * it from the material law. - */ -SET_TYPE_PROP(ThreePThreeC, MaterialLawParams, typename GET_PROP_TYPE(TypeTag, MaterialLaw)::Params); - -//! The local residual function of the conservation equations -SET_TYPE_PROP(ThreePThreeC, LocalResidual, ThreePThreeCLocalResidual<TypeTag>); - -//! Use the 3p3c specific newton controller for the 3p3c model -SET_TYPE_PROP(ThreePThreeC, NewtonController, ThreePThreeCNewtonController<TypeTag>); - -//! the Model property -SET_TYPE_PROP(ThreePThreeC, Model, ThreePThreeCModel<TypeTag>); - -//! the VolumeVariables property -SET_TYPE_PROP(ThreePThreeC, VolumeVariables, ThreePThreeCVolumeVariables<TypeTag>); - -//! the FluxVariables property -SET_TYPE_PROP(ThreePThreeC, FluxVariables, ThreePThreeCFluxVariables<TypeTag>); - -//! define the base flux variables to realize Darcy flow -SET_TYPE_PROP(ThreePThreeC, BaseFluxVariables, ImplicitDarcyFluxVariables<TypeTag>); - -//! the upwind factor for the mobility. -SET_SCALAR_PROP(ThreePThreeC, ImplicitMassUpwindWeight, 1.0); - -//! set default mobility upwind weight to 1.0, i.e. fully upwind -SET_SCALAR_PROP(ThreePThreeC, ImplicitMobilityUpwindWeight, 1.0); - -//! Determines whether a constraint solver should be used explicitly -SET_BOOL_PROP(ThreePThreeC, UseConstraintSolver, false); - -//! The indices required by the isothermal 3p3c model -SET_TYPE_PROP(ThreePThreeC, Indices, ThreePThreeCIndices<TypeTag, /*PVOffset=*/0>); - -//! The spatial parameters to be employed. -//! Use ImplicitSpatialParams by default. -SET_TYPE_PROP(ThreePThreeC, SpatialParams, ImplicitSpatialParams<TypeTag>); - -//! The model after Millington (1961) is used for the effective diffusivity -SET_PROP(ThreePThreeC, EffectiveDiffusivityModel) -{ private : - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - public: - typedef DiffusivityMillingtonQuirk<Scalar> type; -}; - -// disable velocity output by default -SET_BOOL_PROP(ThreePThreeC, VtkAddVelocity, false); - -// enable gravity by default -SET_BOOL_PROP(ThreePThreeC, ProblemEnableGravity, true); - -//! default value for the forchheimer coefficient -// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. -// Actually the Forchheimer coefficient is also a function of the dimensions of the -// porous medium. Taking it as a constant is only a first approximation -// (Nield, Bejan, Convection in porous media, 2006, p. 10) -SET_SCALAR_PROP(BoxModel, SpatialParamsForchCoeff, 0.55); - -//! Somerton is used as default model to compute the effective thermal heat conductivity -SET_PROP(ThreePThreeCNI, ThermalConductivityModel) -{ -private: - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; -public: - typedef ThermalConductivitySomerton<Scalar, Indices> type; -}; - -//! temperature is already written by the isothermal model -SET_BOOL_PROP(ThreePThreeCNI, NiOutputLevel, 0); - -////////////////////////////////////////////////////////////////// -// Property values for isothermal model required for the general non-isothermal model -////////////////////////////////////////////////////////////////// - -// set isothermal Model -SET_TYPE_PROP(ThreePThreeCNI, IsothermalModel, ThreePThreeCModel<TypeTag>); - -// set isothermal FluxVariables -SET_TYPE_PROP(ThreePThreeCNI, IsothermalFluxVariables, ThreePThreeCFluxVariables<TypeTag>); - -//set isothermal VolumeVariables -SET_TYPE_PROP(ThreePThreeCNI, IsothermalVolumeVariables, ThreePThreeCVolumeVariables<TypeTag>); - -//set isothermal LocalResidual -SET_TYPE_PROP(ThreePThreeCNI, IsothermalLocalResidual, ThreePThreeCLocalResidual<TypeTag>); - -//set isothermal Indices -SET_PROP(ThreePThreeCNI, IsothermalIndices) -{ - -public: - typedef ThreePThreeCIndices<TypeTag, /*PVOffset=*/0> type; -}; - -//set isothermal NumEq -SET_INT_PROP(ThreePThreeCNI, IsothermalNumEq, 3); - -} - -} +#include <dumux/porousmediumflow/3p3c/implicit/propertydefaults.hh> #endif diff --git a/dumux/implicit/3p3c/3p3cvolumevariables.hh b/dumux/implicit/3p3c/3p3cvolumevariables.hh index 58a71d6ea8..f538b0b6cc 100644 --- a/dumux/implicit/3p3c/3p3cvolumevariables.hh +++ b/dumux/implicit/3p3c/3p3cvolumevariables.hh @@ -1,750 +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 Contains the quantities which are constant within a - * finite volume in the three-phase three-component model. - */ -#ifndef DUMUX_3P3C_VOLUME_VARIABLES_HH -#define DUMUX_3P3C_VOLUME_VARIABLES_HH +#ifndef DUMUX_3P3C_VOLUME_VARIABLES_HH_OLD +#define DUMUX_3P3C_VOLUME_VARIABLES_HH_OLD -#include <dumux/implicit/model.hh> -#include <dumux/material/constants.hh> -#include <dumux/material/fluidstates/compositionalfluidstate.hh> -#include <dumux/material/constraintsolvers/computefromreferencephase.hh> -#include <dumux/material/constraintsolvers/misciblemultiphasecomposition.hh> -#include "3p3cproperties.hh" +#warning this header is deprecated, use dumux/porousmediumflow/3p3c/implicit/volumevariables.hh instead -namespace Dumux -{ - -/*! - * \ingroup ThreePThreeCModel - * \ingroup ImplicitVolumeVariables - * \brief Contains the quantities which are are constant within a - * finite volume in the three-phase three-component model. - */ -template <class TypeTag> -class ThreePThreeCVolumeVariables : public ImplicitVolumeVariables<TypeTag> -{ - typedef ImplicitVolumeVariables<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; - - // constraint solvers - typedef Dumux::MiscibleMultiPhaseComposition<Scalar, FluidSystem> MiscibleMultiPhaseComposition; - typedef Dumux::ComputeFromReferencePhase<Scalar, FluidSystem> ComputeFromReferencePhase; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - dim = GridView::dimension, - - numPhases = GET_PROP_VALUE(TypeTag, NumPhases), - numComponents = GET_PROP_VALUE(TypeTag, NumComponents), - - wCompIdx = Indices::wCompIdx, - gCompIdx = Indices::gCompIdx, - nCompIdx = Indices::nCompIdx, - - wPhaseIdx = Indices::wPhaseIdx, - gPhaseIdx = Indices::gPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - - switch1Idx = Indices::switch1Idx, - switch2Idx = Indices::switch2Idx, - pressureIdx = Indices::pressureIdx - }; - - // present phases - enum { - threePhases = Indices::threePhases, - wPhaseOnly = Indices::wPhaseOnly, - gnPhaseOnly = Indices::gnPhaseOnly, - wnPhaseOnly = Indices::wnPhaseOnly, - gPhaseOnly = Indices::gPhaseOnly, - wgPhaseOnly = Indices::wgPhaseOnly - }; - - typedef typename GridView::template Codim<0>::Entity Element; - - static const Scalar R; // universial gas constant - - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - enum { dofCodim = isBox ? dim : 0 }; - -public: - - typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; - - /*! - * \copydoc ImplicitVolumeVariables::update - */ - void update(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx, - bool isOldSol) - { - ParentType::update(priVars, - problem, - element, - fvGeometry, - scvIdx, - isOldSol); - - bool useConstraintSolver = GET_PROP_VALUE(TypeTag, UseConstraintSolver); - - // capillary pressure parameters - const MaterialLawParams &materialParams = - problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); - - int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); - int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); - - Scalar temp = Implementation::temperature_(priVars, problem, element, fvGeometry, scvIdx); - fluidState_.setTemperature(temp); - - /* first the saturations */ - if (phasePresence == threePhases) - { - sw_ = priVars[switch1Idx]; - sn_ = priVars[switch2Idx]; - sg_ = 1. - sw_ - sn_; - } - else if (phasePresence == wPhaseOnly) - { - sw_ = 1.; - sn_ = 0.; - sg_ = 0.; - } - else if (phasePresence == gnPhaseOnly) - { - sw_ = 0.; - sn_ = priVars[switch2Idx]; - sg_ = 1. - sn_; - } - else if (phasePresence == wnPhaseOnly) - { - sn_ = priVars[switch2Idx]; - sw_ = 1. - sn_; - sg_ = 0.; - } - else if (phasePresence == gPhaseOnly) - { - sw_ = 0.; - sn_ = 0.; - sg_ = 1.; - } - else if (phasePresence == wgPhaseOnly) - { - sw_ = priVars[switch1Idx]; - sn_ = 0.; - sg_ = 1. - sw_; - } - else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); - Valgrind::CheckDefined(sg_); - - fluidState_.setSaturation(wPhaseIdx, sw_); - fluidState_.setSaturation(gPhaseIdx, sg_); - fluidState_.setSaturation(nPhaseIdx, sn_); - - /* now the pressures */ - pg_ = priVars[pressureIdx]; - - // calculate capillary pressures - Scalar pcgw = MaterialLaw::pcgw(materialParams, sw_); - Scalar pcnw = MaterialLaw::pcnw(materialParams, sw_); - Scalar pcgn = MaterialLaw::pcgn(materialParams, sw_ + sn_); - - Scalar pcAlpha = MaterialLaw::pcAlpha(materialParams, sn_); - Scalar pcNW1 = 0.0; // TODO: this should be possible to assign in the problem file - - pn_ = pg_- pcAlpha * pcgn - (1.-pcAlpha)*(pcgw - pcNW1); - pw_ = pn_ - pcAlpha * pcnw - (1.-pcAlpha)*pcNW1; - - fluidState_.setPressure(wPhaseIdx, pw_); - fluidState_.setPressure(gPhaseIdx, pg_); - fluidState_.setPressure(nPhaseIdx, pn_); - - // calculate and set all fugacity coefficients. this is - // possible because we require all phases to be an ideal - // mixture, i.e. fugacity coefficients are not supposed to - // depend on composition! - typename FluidSystem::ParameterCache paramCache; - // assert(FluidSystem::isIdealGas(gPhaseIdx)); - for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { - assert(FluidSystem::isIdealMixture(phaseIdx)); - - for (int compIdx = 0; compIdx < numComponents; ++ compIdx) { - Scalar phi = FluidSystem::fugacityCoefficient(fluidState_, paramCache, phaseIdx, compIdx); - fluidState_.setFugacityCoefficient(phaseIdx, compIdx, phi); - } - } - - // now comes the tricky part: calculate phase composition - if (phasePresence == threePhases) { - // all phases are present, phase compositions are a - // result of the the gas <-> liquid equilibrium. This is - // the job of the "MiscibleMultiPhaseComposition" - // constraint solver ... - if (useConstraintSolver) { - MiscibleMultiPhaseComposition::solve(fluidState_, - paramCache, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - // ... or calculated explicitly this way ... - else { - Scalar partPressH2O = FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx, - wCompIdx) * pw_; - Scalar partPressNAPL = FluidSystem::fugacityCoefficient(fluidState_, - nPhaseIdx, - nCompIdx) * pn_; - Scalar partPressAir = pg_ - partPressH2O - partPressNAPL; - - Scalar xgn = partPressNAPL/pg_; - Scalar xgw = partPressH2O/pg_; - Scalar xgg = partPressAir/pg_; - - // actually, it's nothing else than Henry coefficient - Scalar xwn = partPressNAPL - / (FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,nCompIdx) - * pw_); - Scalar xwg = partPressAir - / (FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,gCompIdx) - * pw_); - Scalar xww = 1.-xwg-xwn; - - Scalar xnn = 1.-2.e-10; - Scalar xna = 1.e-10; - Scalar xnw = 1.e-10; - - fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); - fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); - fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); - fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); - fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); - fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); - fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); - fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); - fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); - - Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); - Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); - Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); - - fluidState_.setDensity(wPhaseIdx, rhoW); - fluidState_.setDensity(gPhaseIdx, rhoG); - fluidState_.setDensity(nPhaseIdx, rhoN); - } - } - else if (phasePresence == wPhaseOnly) { - // only the water phase is present, water phase composition is - // stored explicitly. - - // extract mole fractions in the water phase - Scalar xwg = priVars[switch1Idx]; - Scalar xwn = priVars[switch2Idx]; - Scalar xww = 1 - xwg - xwn; - - // write water mole fractions in the fluid state - fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); - fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); - fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase" constraint solver ... - if (useConstraintSolver) - { - ComputeFromReferencePhase::solve(fluidState_, - paramCache, - wPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - // ... or calculated explicitly this way ... - else { - // note that the gas phase is actually not existing! - // thus, this is used as phase switch criterion - Scalar xgg = xwg * FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,gCompIdx) - * pw_ / pg_; - Scalar xgn = xwn * FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,nCompIdx) - * pw_ / pg_; - Scalar xgw = FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,wCompIdx) - * pw_ / pg_; - - - // note that the gas phase is actually not existing! - // thus, this is used as phase switch criterion - Scalar xnn = xwn * FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,nCompIdx) - * pw_; - Scalar xna = 1.e-10; - Scalar xnw = 1.e-10; - - fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); - fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); - fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); - fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); - fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); - fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); - - Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); - Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); - Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); - - fluidState_.setDensity(wPhaseIdx, rhoW); - fluidState_.setDensity(gPhaseIdx, rhoG); - fluidState_.setDensity(nPhaseIdx, rhoN); - } - } - else if (phasePresence == gnPhaseOnly) { - // only gas and NAPL phases are present - // we have all (partly hypothetical) phase pressures - // and temperature and the mole fraction of water in - // the gas phase - - // we have all (partly hypothetical) phase pressures - // and temperature and the mole fraction of water in - // the gas phase - Scalar partPressNAPL = fluidState_.fugacityCoefficient(nPhaseIdx, nCompIdx)*pn_; - - Scalar xgw = priVars[switch1Idx]; - Scalar xgn = partPressNAPL/pg_; - Scalar xgg = 1.-xgw-xgn; - - // write mole fractions in the fluid state - fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); - fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); - fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase" constraint solver - ComputeFromReferencePhase::solve(fluidState_, - paramCache, - gPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - else if (phasePresence == wnPhaseOnly) { - // only water and NAPL phases are present - Scalar pPartialC = fluidState_.fugacityCoefficient(nPhaseIdx,nCompIdx)*pn_; - Scalar henryC = fluidState_.fugacityCoefficient(wPhaseIdx,nCompIdx)*pw_; - - Scalar xwg = priVars[switch1Idx]; - Scalar xwn = pPartialC/henryC; - Scalar xww = 1.-xwg-xwn; - - // write mole fractions in the fluid state - fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); - fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); - fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase" constraint solver - ComputeFromReferencePhase::solve(fluidState_, - paramCache, - wPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - else if (phasePresence == gPhaseOnly) { - // only the gas phase is present, gas phase composition is - // stored explicitly here below. - - const Scalar xgw = priVars[switch1Idx]; - const Scalar xgn = priVars[switch2Idx]; - Scalar xgg = 1 - xgw - xgn; - - // write mole fractions in the fluid state - fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); - fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); - fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase" constraint solver ... - if (useConstraintSolver) - { - ComputeFromReferencePhase::solve(fluidState_, - paramCache, - gPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - // ... or calculated explicitly this way ... - else { - - // note that the water phase is actually not existing! - // thus, this is used as phase switch criterion - Scalar xww = xgw * pg_ - / (FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,wCompIdx) - * pw_); - Scalar xwn = 1.e-10; - Scalar xwg = 1.e-10; - - // note that the NAPL phase is actually not existing! - // thus, this is used as phase switch criterion - Scalar xnn = xgn * pg_ - / (FluidSystem::fugacityCoefficient(fluidState_, - nPhaseIdx,nCompIdx) - * pn_); - Scalar xna = 1.e-10; - Scalar xnw = 1.e-10; - - fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); - fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); - fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); - fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); - fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); - fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); - - Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); - Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); - Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); - - fluidState_.setDensity(wPhaseIdx, rhoW); - fluidState_.setDensity(gPhaseIdx, rhoG); - fluidState_.setDensity(nPhaseIdx, rhoN); - } - } - else if (phasePresence == wgPhaseOnly) { - // only water and gas phases are present - Scalar xgn = priVars[switch2Idx]; - Scalar partPressH2O = fluidState_.fugacityCoefficient(wPhaseIdx, wCompIdx)*pw_; - - Scalar xgw = partPressH2O/pg_; - Scalar xgg = 1.-xgn-xgw; - - // write mole fractions in the fluid state - fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); - fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); - fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); - - // calculate the composition of the remaining phases (as - // well as the densities of all phases). this is the job - // of the "ComputeFromReferencePhase" constraint solver ... - if (useConstraintSolver) - { - ComputeFromReferencePhase::solve(fluidState_, - paramCache, - gPhaseIdx, - /*setViscosity=*/true, - /*setInternalEnergy=*/false); - } - // ... or calculated explicitly this way ... - else { - // actually, it's nothing else than Henry coefficient - Scalar xwn = xgn * pg_ - / (FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,nCompIdx) - * pw_); - Scalar xwg = xgg * pg_ - / (FluidSystem::fugacityCoefficient(fluidState_, - wPhaseIdx,gCompIdx) - * pw_); - Scalar xww = 1.-xwg-xwn; - - // note that the NAPL phase is actually not existing! - // thus, this is used as phase switch criterion - Scalar xnn = xgn * pg_ - / (FluidSystem::fugacityCoefficient(fluidState_, - nPhaseIdx,nCompIdx) - * pn_); - Scalar xna = 1.e-10; - Scalar xnw = 1.e-10; - - fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); - fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); - fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); - fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); - fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); - fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); - - Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); - Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); - Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); - - fluidState_.setDensity(wPhaseIdx, rhoW); - fluidState_.setDensity(gPhaseIdx, rhoG); - fluidState_.setDensity(nPhaseIdx, rhoN); - } - } - else - assert(false); // unhandled phase state - - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - // Mobilities - const Scalar mu = - FluidSystem::viscosity(fluidState_, - paramCache, - phaseIdx); - fluidState_.setViscosity(phaseIdx,mu); - - Scalar kr; - kr = MaterialLaw::kr(materialParams, phaseIdx, - fluidState_.saturation(wPhaseIdx), - fluidState_.saturation(nPhaseIdx), - fluidState_.saturation(gPhaseIdx)); - mobility_[phaseIdx] = kr / mu; - Valgrind::CheckDefined(mobility_[phaseIdx]); - } - - // material dependent parameters for NAPL adsorption - bulkDensTimesAdsorpCoeff_ = - MaterialLaw::bulkDensTimesAdsorpCoeff(materialParams); - - /* ATTENTION: The conversion to effective diffusion parameters - * for the porous media happens at another place! - */ - - // diffusivity coefficents - diffusionCoefficient_[gPhaseIdx][wCompIdx] = - FluidSystem::diffusionCoefficient(fluidState_, - paramCache, - gPhaseIdx, - wCompIdx); - diffusionCoefficient_[gPhaseIdx][nCompIdx] = - FluidSystem::diffusionCoefficient(fluidState_, - paramCache, - gPhaseIdx, - nCompIdx); - diffusionCoefficient_[gPhaseIdx][gCompIdx] = 0.0; // dummy, should not be used ! - - diffusionCoefficient_[wPhaseIdx][gCompIdx] = - FluidSystem::diffusionCoefficient(fluidState_, - paramCache, - wPhaseIdx, - gCompIdx); - diffusionCoefficient_[wPhaseIdx][nCompIdx] = - FluidSystem::diffusionCoefficient(fluidState_, - paramCache, - wPhaseIdx, - nCompIdx); - diffusionCoefficient_[wPhaseIdx][wCompIdx] = 0.0; // dummy, should not be used ! - - /* no diffusion in NAPL phase considered at the moment */ - diffusionCoefficient_[nPhaseIdx][nCompIdx] = 0.0; - diffusionCoefficient_[nPhaseIdx][wCompIdx] = 0.0; - diffusionCoefficient_[nPhaseIdx][gCompIdx] = 0.0; - - Valgrind::CheckDefined(diffusionCoefficient_); - - // porosity - porosity_ = problem.spatialParams().porosity(element, - fvGeometry, - scvIdx); - Valgrind::CheckDefined(porosity_); - - // energy related quantities not contained in the fluid state - asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol); - // compute and set the enthalpy - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - Scalar h = Implementation::enthalpy_(fluidState_, paramCache, phaseIdx); - fluidState_.setEnthalpy(phaseIdx, h); - } - } - - /*! - * \brief Returns the phase state for the control volume. - */ - const FluidState &fluidState() const - { return fluidState_; } - - /*! - * \brief Returns the effective saturation of a given phase within - * the control volume. - * - * \param phaseIdx The phase index - */ - Scalar saturation(const int phaseIdx) const - { return fluidState_.saturation(phaseIdx); } - - /*! - * \brief Returns the mass fraction of a given component in a - * given phase within the control volume in \f$[-]\f$. - * - * \param phaseIdx The phase index - * \param compIdx The component index - */ - Scalar massFraction(const int phaseIdx, const int compIdx) const - { return fluidState_.massFraction(phaseIdx, compIdx); } - - /*! - * \brief Returns the mole fraction of a given component in a - * given phase within the control volume in \f$[-]\f$. - * - * \param phaseIdx The phase index - * \param compIdx The component index - */ - Scalar moleFraction(const int phaseIdx, const int compIdx) const - { return fluidState_.moleFraction(phaseIdx, compIdx); } - - /*! - * \brief Returns the mass density of a given phase within the - * control volume. - * - * \param phaseIdx The phase index - */ - Scalar density(const int phaseIdx) const - { return fluidState_.density(phaseIdx); } - - /*! - * \brief Returns the molar density of a given phase within the - * control volume. - * - * \param phaseIdx The phase index - */ - Scalar molarDensity(const int phaseIdx) const - { return fluidState_.density(phaseIdx) / fluidState_.averageMolarMass(phaseIdx); } - - /*! - * \brief Returns the effective pressure of a given phase within - * the control volume. - * - * \param phaseIdx The phase index - */ - Scalar pressure(const int phaseIdx) const - { return fluidState_.pressure(phaseIdx); } - - /*! - * \brief Returns temperature inside the sub-control volume. - * - * Note that we assume thermodynamic equilibrium, i.e. the - * temperatures of the rock matrix and of all fluid phases are - * identical. - */ - Scalar temperature() const - { return fluidState_.temperature(/*phaseIdx=*/0); } - - /*! - * \brief Returns the effective mobility of a given phase within - * the control volume. - * - * \param phaseIdx The phase index - */ - Scalar mobility(const int phaseIdx) const - { - return mobility_[phaseIdx]; - } - - /*! - * \brief Returns the effective capillary pressure within the control volume. - */ - Scalar capillaryPressure() const - { return fluidState_.capillaryPressure(); } - - /*! - * \brief Returns the average porosity within the control volume. - */ - Scalar porosity() const - { return porosity_; } - - /*! - * \brief Returns the diffusivity coefficient matrix. - */ - Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficient() const - { return diffusionCoefficient_; } - - /*! - * \brief Returns the adsorption information. - */ - Scalar bulkDensTimesAdsorpCoeff() const - { return bulkDensTimesAdsorpCoeff_; } - - -protected: - - static Scalar temperature_(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx) - { - return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); - } - - /*! - * \brief Called by update() to compute the energy related quantities - */ - void updateEnergy_(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx, - bool isOldSol) - { } - - template<class ParameterCache> - static Scalar enthalpy_(const FluidState& fluidState, - const ParameterCache& paramCache, - const int phaseIdx) - { - return 0; - } - - Scalar sw_, sg_, sn_, pg_, pw_, pn_; - - Scalar moleFrac_[numPhases][numComponents]; - Scalar massFrac_[numPhases][numComponents]; - - Scalar porosity_; //!< Effective porosity within the control volume - Scalar mobility_[numPhases]; //!< Effective mobility within the control volume - Scalar bulkDensTimesAdsorpCoeff_; //!< the basis for calculating adsorbed NAPL - /* We need a tensor here !! */ - //!< Binary diffusion coefficients of the 3 components in the phases - Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficient_; - FluidState fluidState_; - -private: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } -}; - -template <class TypeTag> -const typename ThreePThreeCVolumeVariables<TypeTag>::Scalar ThreePThreeCVolumeVariables<TypeTag>::R - = Constants<typename GET_PROP_TYPE(TypeTag, Scalar)>::R; - -} // end namespace +#include <dumux/porousmediumflow/3p3c/implicit/volumevariables.hh> #endif diff --git a/dumux/implicit/co2/co2model.hh b/dumux/implicit/co2/co2model.hh index c84592435f..f4e5867e04 100644 --- a/dumux/implicit/co2/co2model.hh +++ b/dumux/implicit/co2/co2model.hh @@ -24,7 +24,7 @@ #ifndef DUMUX_CO2_MODEL_HH #define DUMUX_CO2_MODEL_HH -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> namespace Dumux { diff --git a/dumux/implicit/co2/co2volumevariables.hh b/dumux/implicit/co2/co2volumevariables.hh index 5836b604d7..d54cd52f3c 100644 --- a/dumux/implicit/co2/co2volumevariables.hh +++ b/dumux/implicit/co2/co2volumevariables.hh @@ -25,7 +25,7 @@ #ifndef DUMUX_CO2_VOLUME_VARIABLES_HH #define DUMUX_CO2_VOLUME_VARIABLES_HH -#include <dumux/implicit/2p2c/2p2cvolumevariables.hh> +#include <dumux/porousmediumflow/2p2c/implicit/volumevariables.hh> namespace Dumux { diff --git a/dumux/multidomain/2cnistokes2p2cni/2p2cnicouplinglocalresidual.hh b/dumux/multidomain/2cnistokes2p2cni/2p2cnicouplinglocalresidual.hh index b701597f45..b8b1df939f 100644 --- a/dumux/multidomain/2cnistokes2p2cni/2p2cnicouplinglocalresidual.hh +++ b/dumux/multidomain/2cnistokes2p2cni/2p2cnicouplinglocalresidual.hh @@ -27,7 +27,7 @@ #include <dune/common/deprecated.hh> #include <dumux/porousmediumflow/nonisothermal/implicit/localresidual.hh> -#include <dumux/implicit/2p2c/2p2cproperties.hh> +#include <dumux/porousmediumflow/2p2c/implicit/properties.hh> namespace Dumux { diff --git a/dumux/multidomain/2cstokes2p2c/2cstokes2p2clocaloperator.hh b/dumux/multidomain/2cstokes2p2c/2cstokes2p2clocaloperator.hh index 853916be13..e07fc31950 100644 --- a/dumux/multidomain/2cstokes2p2c/2cstokes2p2clocaloperator.hh +++ b/dumux/multidomain/2cstokes2p2c/2cstokes2p2clocaloperator.hh @@ -37,7 +37,7 @@ #include <dumux/freeflow/boundarylayermodel.hh> #include <dumux/freeflow/masstransfermodel.hh> #include <dumux/freeflow/stokesnc/stokesncmodel.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> namespace Dumux { diff --git a/dumux/multidomain/2cstokes2p2c/2p2ccouplinglocalresidual.hh b/dumux/multidomain/2cstokes2p2c/2p2ccouplinglocalresidual.hh index 4cf3b7688a..69f154653a 100644 --- a/dumux/multidomain/2cstokes2p2c/2p2ccouplinglocalresidual.hh +++ b/dumux/multidomain/2cstokes2p2c/2p2ccouplinglocalresidual.hh @@ -26,8 +26,8 @@ #include <dune/common/deprecated.hh> -#include <dumux/implicit/2p2c/2p2clocalresidual.hh> -#include <dumux/implicit/2p2c/2p2cproperties.hh> +#include <dumux/porousmediumflow/2p2c/implicit/localresidual.hh> +#include <dumux/porousmediumflow/2p2c/implicit/properties.hh> namespace Dumux { diff --git a/dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh b/dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh new file mode 100644 index 0000000000..bddb873565 --- /dev/null +++ b/dumux/porousmediumflow/1p2c/implicit/fluxvariables.hh @@ -0,0 +1,525 @@ +// -*- 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 + * all fluxes of fluid phases over a face of a finite volume. + * + * This means pressure and mole-fraction gradients, phase densities at + * the integration point, etc. + * + */ +#ifndef DUMUX_1P2C_FLUX_VARIABLES_HH +#define DUMUX_1P2C_FLUX_VARIABLES_HH + +#include "properties.hh" + +#include <dumux/common/math.hh> +#include <dumux/common/valgrind.hh> + +namespace Dumux +{ + +/*! + * \ingroup OnePTwoCModel + * \ingroup ImplicitFluxVariables + * \brief This template class contains the data which is required to + * calculate the fluxes of the fluid phases over a face of a + * finite volume for the one-phase, two-component model. + * + * This means pressure and mole-fraction gradients, phase densities at + * the intergration point, etc. + */ +template <class TypeTag> +class OnePTwoCFluxVariables +{ + 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, SpatialParams) SpatialParams; + typedef typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel) EffectiveDiffusivityModel; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + transportCompIdx = Indices::transportCompIdx + }; + + 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 Dune::FieldVector<CoordScalar, dimWorld> GlobalPosition; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimWorldMatrix; + + 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 scvfIdx 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 + */ + OnePTwoCFluxVariables(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : fvGeometry_(fvGeometry), faceIdx_(fIdx), onBoundary_(onBoundary) + { + mobilityUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MobilityUpwindWeight); + + viscosity_ = Scalar(0); + molarDensity_ = Scalar(0); + density_ = Scalar(0); + potentialGrad_ = Scalar(0); + moleFractionGrad_ = Scalar(0); + + calculateGradients_(problem, element, elemVolVars); + calculateK_(problem, element, elemVolVars); + calculateVelocities_(problem, element, elemVolVars); + calculatePorousDiffCoeff_(problem, element, elemVolVars); + calculateDispersionTensor_(problem, element, elemVolVars); + }; + +public: + /*! + * \brief Return the pressure potential multiplied with the + * intrinsic permeability and the face normal which + * goes from vertex i to vertex j. + * + * Note that the length of the face's normal is the area of the + * phase, so this is not the actual velocity but the integral of + * the velocity over the face's area. Also note that the phase + * mobility is not yet included here since this would require a + * decision on the upwinding approach (which is done in the + * actual model). + */ + Scalar KmvpNormal() const + { return KmvpNormal_; } + + /*! + * \brief Return the pressure potential multiplied with the + * intrinsic permeability as vector (for velocity output). + */ + GlobalPosition Kmvp() const + { return Kmvp_; } + + /*! + * \brief The face of the current sub-control volume. This may be either + * an inner sub-control-volume face or a SCV face on the boundary. + */ + const SCVFace &face() const + { + if (onBoundary_) + return fvGeometry_.boundaryFace[faceIdx_]; + else + return fvGeometry_.subContVolFace[faceIdx_]; + } + + /*! + * \brief Return the intrinsic permeability tensor \f$\mathrm{[m^2]}\f$. + */ + const DimWorldMatrix &intrinsicPermeability() const + { return K_; } + + /*! + * \brief Return the dispersion tensor \f$\mathrm{[m^2/s]}\f$. + */ + const DimWorldMatrix &dispersionTensor() const + { return dispersionTensor_; } + + /*! + * \brief Return the pressure potential gradient \f$\mathrm{[Pa/m]}\f$. + */ + const GlobalPosition &potentialGrad() const + { return potentialGrad_; } + + + /*! + * \brief Return the mole-fraction gradient of a component in a phase \f$\mathrm{[mol/mol/m)]}\f$. + * + * \param compIdx The index of the considered component + */ + const GlobalPosition &moleFractionGrad(int compIdx) const + { + if (compIdx != 1) + { DUNE_THROW(Dune::InvalidStateException, + "The 1p2c model is supposed to need " + "only the concentration gradient of " + "the second component!"); } + return moleFractionGrad_; + }; + + /*! + * \brief The binary diffusion coefficient for each fluid phase in the porous medium \f$\mathrm{[m^2/s]}\f$. + */ + Scalar porousDiffCoeff() const + { + // TODO: tensorial porousDiffCoeff_usion coefficients + return porousDiffCoeff_; + }; + + /*! + * \brief Return viscosity \f$\mathrm{[Pa s]}\f$ of a phase at the integration + * point. + */ + Scalar viscosity() const + { return viscosity_;} + + /*! + * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ of a phase at the integration + * point. + */ + Scalar molarDensity() const + { return molarDensity_; } + + /*! + * \brief Return density \f$\mathrm{[kg/m^3]}\f$ of a phase at the integration + * point. + */ + Scalar density() const + { return density_; } + + /*! + * \brief Given the intrinsic permeability times the pressure + * potential gradient and SCV face normal for a phase, + * return the local index of the upstream control volume + * for a given phase. + * + * \param normalFlux The flux over a face of the sub-control volume + */ + int upstreamIdx(Scalar normalFlux) const + { return (normalFlux >= 0)?face().i:face().j; } + + /*! + * \brief Given the intrinsic permeability times the pressure + * potential gradient and SCV face normal for a phase, + * return the local index of the downstream control volume + * for a given phase. + * + * \param normalFlux The flux over a face of the sub-control volume + */ + int downstreamIdx(Scalar normalFlux) const + { return (normalFlux > 0)?face().j:face().i; } + + /*! + * \brief Return the local index of the upstream control volume + * for a given phase. + */ + int upstreamIdx() const + { return upstreamIdx_; } + + /*! + * \brief Return the local index of the downstream control volume + * for a given phase. + */ + int downstreamIdx() const + { return downstreamIdx_; } + + /*! + * \brief Return the local index of the upstream control volume + * for a given phase. + */ + int upstreamIdx(int phaseIdx) const + { return upstreamIdx_; } + + /*! + * \brief Return the local index of the downstream control volume + * for a given phase. + */ + int downstreamIdx(int phaseIdx) const + { return downstreamIdx_; } + + /*! + * \brief Return the volumetric flux over a face of a given phase. + * + * This is the calculated velocity multiplied by the unit normal + * and the area of the face. + * face().normal + * has already the magnitude of the area. + * + * \param phaseIdx index of the phase + */ + Scalar volumeFlux(const unsigned int phaseIdx) const + { + assert (phaseIdx == Indices::phaseIdx); + return volumeFlux_; + } + +protected: + + /*! + * \brief Calculation of the pressure and mole-/mass-fraction 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) + { + // loop over flux approximation points + for (unsigned int idx = 0; idx < face().numFap; idx++) + { + // FE gradient at vertex idx + const GlobalPosition &feGrad = face().grad[idx]; + + // index for the element volume variables + int volVarsIdx = face().fapIndices[idx]; + + // the pressure gradient + GlobalPosition tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].pressure(); + potentialGrad_ += tmp; + + // the mole-fraction gradient + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(transportCompIdx); + moleFractionGrad_ += tmp; + + // phase viscosity + viscosity_ += elemVolVars[volVarsIdx].viscosity()*face().shapeValue[idx]; + + //phase molar density + molarDensity_ += elemVolVars[volVarsIdx].molarDensity()*face().shapeValue[idx]; + + //phase density + density_ += elemVolVars[volVarsIdx].density()*face().shapeValue[idx]; + } + + + /////////////// + // correct the pressure gradients by the gravitational acceleration + /////////////// + if (GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity)) { + // calculate the phase density at the integration point. we + // only do this if the wetting phase is present in both cells + Scalar rhoI = elemVolVars[face().i].density(); + Scalar rhoJ = elemVolVars[face().j].density(); + Scalar density = (rhoI + rhoJ)/2; + + // ask for the gravitational acceleration at the given SCV face + GlobalPosition g(problem.gravityAtPos(face().ipGlobal)); + + // make it a force + g *= density; + + // calculate the final potential gradient + potentialGrad_ -= g; + } + } + + /*! + * \brief Calculation of the harmonic mean of the intrinsic permeability + * uses the meanK function in the boxspatialparameters.hh file in the folder + * material/spatialparameters + * + * \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) + { + const SpatialParams &sp = problem.spatialParams(); + if (GET_PROP_VALUE(TypeTag, ImplicitIsBox)) + { + sp.meanK(K_, + sp.intrinsicPermeability(element, + fvGeometry_, + face().i), + sp.intrinsicPermeability(element, + fvGeometry_, + face().j)); + } + else + { + const Element& elementI = fvGeometry_.neighbors[face().i]; + FVElementGeometry fvGeometryI; + fvGeometryI.subContVol[0].global = elementI.geometry().center(); + + const Element& elementJ = fvGeometry_.neighbors[face().j]; + FVElementGeometry fvGeometryJ; + fvGeometryJ.subContVol[0].global = elementJ.geometry().center(); + + sp.meanK(K_, + sp.intrinsicPermeability(elementI, fvGeometryI, 0), + sp.intrinsicPermeability(elementJ, fvGeometryJ, 0)); + } + } + + /*! + * \brief Calculation of the velocity normal to face using Darcy's law. + * Tensorial permeability is multiplied with the potential gradient and the face normal. + * Identify upstream node of face. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateVelocities_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + K_.mv(potentialGrad_, Kmvp_); + KmvpNormal_ = -(Kmvp_*face().normal); + + // set the upstream and downstream vertices + upstreamIdx_ = face().i; + downstreamIdx_ = face().j; + + if (KmvpNormal_ < 0) + { + std::swap(upstreamIdx_, + downstreamIdx_); + } + + volumeFlux_ = KmvpNormal_; + volumeFlux_ *= mobilityUpwindWeight_/elemVolVars[upstreamIdx_].viscosity() + + (1.0 - mobilityUpwindWeight_)/elemVolVars[downstreamIdx_].viscosity(); + } + /*! + * \brief Calculation of the effective 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 calculatePorousDiffCoeff_(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()); + + // -> harmonic mean + porousDiffCoeff_ = harmonicMean(diffCoeffI, diffCoeffJ); + } + + /*! + * \brief Calculation of the dispersion. + * + * \param problem The considered problem file + * \param element The considered element of the grid + * \param elemVolVars The parameters stored in the considered element + */ + void calculateDispersionTensor_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + const VolumeVariables &volVarsI = elemVolVars[face().i]; + const VolumeVariables &volVarsJ = elemVolVars[face().j]; + + //calculate dispersivity at the interface: [0]: alphaL = longitudinal disp. [m], [1] alphaT = transverse disp. [m] + Scalar dispersivity[2]; + dispersivity[0] = 0.5 * (volVarsI.dispersivity()[0] + volVarsJ.dispersivity()[0]); + dispersivity[1] = 0.5 * (volVarsI.dispersivity()[1] + volVarsJ.dispersivity()[1]); + + //calculate velocity at interface: v = -1/mu * vDarcy = -1/mu * K * grad(p) + GlobalPosition velocity; + Valgrind::CheckDefined(potentialGrad()); + Valgrind::CheckDefined(K_); + K_.mv(potentialGrad(), velocity); + velocity /= - 0.5 * (volVarsI.viscosity() + volVarsJ.viscosity()); + + //matrix multiplication of the velocity at the interface: vv^T + dispersionTensor_ = 0; + for (int i=0; i<dim; i++) + for (int j = 0; j<dim; j++) + dispersionTensor_[i][j] = velocity[i]*velocity[j]; + + //normalize velocity product --> vv^T/||v||, [m/s] + Scalar vNorm = velocity.two_norm(); + + dispersionTensor_ /= vNorm; + if (vNorm < 1e-20) + dispersionTensor_ = 0; + + //multiply with dispersivity difference: vv^T/||v||*(alphaL - alphaT), [m^2/s] --> alphaL = longitudinal disp., alphaT = transverse disp. + dispersionTensor_ *= (dispersivity[0] - dispersivity[1]); + + //add ||v||*alphaT to the main diagonal:vv^T/||v||*(alphaL - alphaT) + ||v||*alphaT, [m^2/s] + for (int i = 0; i<dim; i++) + dispersionTensor_[i][i] += vNorm*dispersivity[1]; + } + + const FVElementGeometry &fvGeometry_; + const int faceIdx_; + const bool onBoundary_; + + //! pressure potential gradient + GlobalPosition potentialGrad_; + //! mole-fraction gradient + GlobalPosition moleFractionGrad_; + //! the effective diffusion coefficent in the porous medium + Scalar porousDiffCoeff_; + + //! the dispersion tensor in the porous medium + DimWorldMatrix dispersionTensor_; + + //! the intrinsic permeability tensor + DimWorldMatrix K_; + // intrinsic permeability times pressure potential gradient + GlobalPosition Kmvp_; + // projected on the face normal + Scalar KmvpNormal_; + + // local index of the upwind vertex for each phase + int upstreamIdx_; + // local index of the downwind vertex for each phase + int downstreamIdx_; + + //! viscosity of the fluid at the integration point + Scalar viscosity_; + + //! molar densities of the fluid at the integration point + Scalar molarDensity_, density_; + + Scalar volumeFlux_; //!< Velocity multiplied with normal (magnitude=area) + Scalar mobilityUpwindWeight_; //!< Upwind weight for mobility. Set to one for full upstream weighting +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/1p2c/implicit/indices.hh b/dumux/porousmediumflow/1p2c/implicit/indices.hh new file mode 100644 index 0000000000..274b58b30f --- /dev/null +++ b/dumux/porousmediumflow/1p2c/implicit/indices.hh @@ -0,0 +1,63 @@ +// -*- 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 1p2c model + */ + +#ifndef DUMUX_1P2C_INDICES_HH +#define DUMUX_1P2C_INDICES_HH + +#include "properties.hh" + +namespace Dumux +{ +// \{ + +/*! + * \ingroup OnePTwoCModel + * \ingroup ImplicitIndices + * \brief The indices for the isothermal single-phase, two-component model. + */ +template <class TypeTag, int PVOffset = 0> +struct OnePTwoCIndices +{ + + //! Set the default phase used by the fluid system to the first one + static const int phaseIdx = GET_PROP_VALUE(TypeTag, PhaseIdx); + + //! Component indices + static const int phaseCompIdx = phaseIdx;//!< The index of the main component of the considered phase + //! The index of the transported (minor) component; ASSUMES phase indices of 0 and 1 + static const int transportCompIdx = (unsigned int)(1-phaseIdx); + + // Equation indices + static const int conti0EqIdx = PVOffset + 0; //!< continuity equation index + static const int transportEqIdx = PVOffset + 1; //!< transport equation index + + // primary variable indices + static const int pressureIdx = PVOffset + 0; //!< pressure + static const int massOrMoleFracIdx = PVOffset + 1; //!< mole fraction of the second component +}; + +// \} +} + +#endif diff --git a/dumux/porousmediumflow/1p2c/implicit/localresidual.hh b/dumux/porousmediumflow/1p2c/implicit/localresidual.hh new file mode 100644 index 0000000000..e6640cd2f5 --- /dev/null +++ b/dumux/porousmediumflow/1p2c/implicit/localresidual.hh @@ -0,0 +1,265 @@ +// -*- 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 single-phase, + * two-component model in the fully implicit scheme. + */ + +#ifndef DUMUX_ONEP_TWOC_LOCAL_RESIDUAL_HH +#define DUMUX_ONEP_TWOC_LOCAL_RESIDUAL_HH + +#include "properties.hh" + +namespace Dumux +{ +/*! + * + * \ingroup OnePTwoCModel + * \ingroup ImplicitLocalResidual + * \brief Calculate the local Jacobian for the single-phase, + * two-component model in the fully implicit scheme. + * + * This class is used to fill the gaps in BoxLocalResidual for the 1p2c flow and transport. + */ +template<class TypeTag> +class OnePTwoCLocalResidual : 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 }; + enum { dimWorld = GridView::dimensionworld }; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + + 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, 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. + */ + OnePTwoCLocalResidual() + { + // 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); + }; + + /*! + * \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, const int scvIdx, const 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; + if(useMoles) // mole-fraction formulation + { + // storage term of continuity equation- molefractions + //careful: molarDensity changes with moleFrac! + storage[conti0EqIdx] += volVars.molarDensity()*volVars.porosity(); + // storage term of the transport equation - molefractions + storage[transportEqIdx] += + volVars.molarDensity()*volVars.moleFraction(transportCompIdx) * + volVars.porosity(); + } + else // mass-fraction formulation + { + // storage term of continuity equation - massfractions + storage[conti0EqIdx] += + volVars.density()*volVars.porosity(); + //storage term of the transport equation - massfractions + storage[transportEqIdx] += + volVars.density() * volVars.massFraction(transportCompIdx) * volVars.porosity(); + } + } + + /*! + * \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, const int fIdx, const bool onBoundary=false) const + { + flux = 0; + FluxVariables fluxVars(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_(), + onBoundary); + + asImp_()->computeAdvectiveFlux(flux, fluxVars); + asImp_()->computeDiffusiveFlux(flux, fluxVars); + } + + /*! + * \brief Evaluate 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 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()); + + if(!useMoles) //mass-fraction formulation + { + // total mass flux - massfraction + //KmvpNormal is the Darcy velocity multiplied with the normal vector, calculated in 1p2cfluxvariables.hh + flux[conti0EqIdx] += + fluxVars.KmvpNormal() * + (( upwindWeight_)*up.density()/up.viscosity() + + + ((1 - upwindWeight_)*dn.density()/dn.viscosity())); + + // advective flux of the second component - massfraction + flux[transportEqIdx] += + fluxVars.KmvpNormal() * + (( upwindWeight_)*up.density() * up.massFraction(transportCompIdx)/up.viscosity() + + + (1 - upwindWeight_)*dn.density()*dn.massFraction(transportCompIdx)/dn.viscosity()); + } + else //mole-fraction formulation + { + // total mass flux - molefraction + //KmvpNormal is the Darcy velocity multiplied with the normal vector, calculated in 1p2cfluxvariables.hh + flux[conti0EqIdx] += + fluxVars.KmvpNormal() * + (( upwindWeight_)*up.molarDensity()/up.viscosity() + + + ((1 - upwindWeight_)*dn.molarDensity()/dn.viscosity())); + + // advective flux of the second component -molefraction + flux[transportEqIdx] += + fluxVars.KmvpNormal() * + (( upwindWeight_)*up.molarDensity() * up.moleFraction(transportCompIdx)/up.viscosity() + + + (1 - upwindWeight_)*dn.molarDensity() * dn.moleFraction(transportCompIdx)/dn.viscosity()); + } + + } + + /*! + * \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 SCV + */ + void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + { + Scalar tmp(0); + + // diffusive flux of second component + if(useMoles) // mole-fraction formulation + { + // diffusive flux of the second component - molefraction + tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); + tmp *= fluxVars.porousDiffCoeff() * fluxVars.molarDensity(); + + // dispersive flux of second component - molefraction + GlobalPosition normalDisp; + fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); + tmp -= fluxVars.molarDensity()* + (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); + + flux[transportEqIdx] += tmp; + } + else // mass-fraction formulation + { + // diffusive flux of the second component - massfraction + tmp = -(fluxVars.moleFractionGrad(transportCompIdx)*fluxVars.face().normal); + tmp *= fluxVars.porousDiffCoeff() * fluxVars.molarDensity(); + + // dispersive flux of second component - massfraction + GlobalPosition normalDisp; + fluxVars.dispersionTensor().mv(fluxVars.face().normal, normalDisp); + tmp -= fluxVars.molarDensity()* + (normalDisp * fluxVars.moleFractionGrad(transportCompIdx)); + + // convert it to a mass flux and add it + flux[transportEqIdx] += tmp * FluidSystem::molarMass(transportCompIdx); + } + } + + Implementation *asImp_() + { return static_cast<Implementation *> (this); } + const Implementation *asImp_() const + { return static_cast<const Implementation *> (this); } + +private: + Scalar upwindWeight_; +}; + +} + +#endif diff --git a/dumux/porousmediumflow/1p2c/implicit/model.hh b/dumux/porousmediumflow/1p2c/implicit/model.hh new file mode 100644 index 0000000000..f8d8a9fad7 --- /dev/null +++ b/dumux/porousmediumflow/1p2c/implicit/model.hh @@ -0,0 +1,194 @@ +// -*- 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 single-phase, + * two-component fully implicit model. + * Adaption of the fully implicit scheme to the one-phase two-component flow model. + */ + +#ifndef DUMUX_ONEP_TWOC_MODEL_HH +#define DUMUX_ONEP_TWOC_MODEL_HH + +#include <dumux/porousmediumflow/implicit/velocityoutput.hh> +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup OnePTwoCModel + * \brief Adaption of the fully implicit scheme to the one-phase two-component flow model. + * + * This model implements a one-phase flow of a compressible fluid, that consists of two components, + * using a standard Darcy + * approach as the equation for the conservation of momentum: + \f[ + v = - \frac{\textbf K}{\mu} + \left(\textbf{grad}\, p - \varrho {\textbf g} \right) + \f] + * + * Gravity can be enabled or disabled via the property system. + * By inserting this into the continuity equation, one gets + \f[ + \phi\frac{\partial \varrho}{\partial t} - \text{div} \left\{ + \varrho \frac{\textbf K}{\mu} \left(\textbf{grad}\, p - \varrho {\textbf g} \right) + \right\} = q \;, + \f] + * + * The transport of the components \f$\kappa \in \{ w, a \}\f$ is described by the following equation: + \f[ + \phi \frac{ \partial \varrho X^\kappa}{\partial t} + - \text{div} \left\lbrace \varrho X^\kappa \frac{{\textbf K}}{\mu} \left( \textbf{grad}\, p - + \varrho {\textbf g} \right) + + \varrho D^\kappa_\text{pm} \frac{M^\kappa}{M_\alpha} \textbf{grad} x^\kappa \right\rbrace = q. + \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 model is able to use either mole or mass fractions. The property useMoles can be set to either true or false in the + * problem file. Make sure that the according units are used in the problem setup. useMoles is set to true by default. + * + * The primary variables are the pressure \f$p\f$ and the mole or mass fraction of dissolved component \f$x\f$. + */ + +template<class TypeTag > +class OnePTwoCModel : public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { dim = GridView::dimension }; + enum { dimWorld = GridView::dimensionworld }; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { phaseIdx = Indices::phaseIdx }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + +public: + /*! + * \brief \copybrief ImplicitModel::addOutputVtkFields + * + * Specialization for the OnePTwoCModel, adding pressure, + * mass and mole fractions, and the process rank to the VTK writer. + */ + template<class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, + MultiWriter &writer) + { + typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<double, dimWorld> > VectorField; + + // create the required scalar fields + unsigned numDofs = this->numDofs(); + ScalarField &pressure = *writer.allocateManagedBuffer(numDofs); + ScalarField &delp = *writer.allocateManagedBuffer(numDofs); + ScalarField &moleFraction0 = *writer.allocateManagedBuffer(numDofs); + ScalarField &moleFraction1 = *writer.allocateManagedBuffer(numDofs); + ScalarField &massFraction0 = *writer.allocateManagedBuffer(numDofs); + ScalarField &massFraction1 = *writer.allocateManagedBuffer(numDofs); + ScalarField &rho = *writer.allocateManagedBuffer(numDofs); + ScalarField &mu = *writer.allocateManagedBuffer(numDofs); + VectorField *velocity = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); + ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); + + if (velocityOutput.enableOutput()) + { + // initialize velocity field + for (unsigned int i = 0; i < numDofs; ++i) + { + (*velocity)[i] = Scalar(0); + } + } + + unsigned numElements = this->gridView_().size(0); + ScalarField &rank = *writer.allocateManagedBuffer(numElements); + + 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(); + + FVElementGeometry fvGeometry; + fvGeometry.update(this->gridView_(), element); + + ElementVolumeVariables elemVolVars; + elemVolVars.update(this->problem_(), + element, + fvGeometry, + false /* oldSol? */); + + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); + + pressure[dofIdxGlobal] = elemVolVars[scvIdx].pressure(); + delp[dofIdxGlobal] = elemVolVars[scvIdx].pressure() - 1e5; + moleFraction0[dofIdxGlobal] = elemVolVars[scvIdx].moleFraction(0); + moleFraction1[dofIdxGlobal] = elemVolVars[scvIdx].moleFraction(1); + massFraction0[dofIdxGlobal] = elemVolVars[scvIdx].massFraction(0); + massFraction1[dofIdxGlobal] = elemVolVars[scvIdx].massFraction(1); + rho[dofIdxGlobal] = elemVolVars[scvIdx].density(); + mu[dofIdxGlobal] = elemVolVars[scvIdx].viscosity(); + } + + // velocity output + velocityOutput.calculateVelocity(*velocity, elemVolVars, fvGeometry, element, phaseIdx); + } + } + + writer.attachDofData(pressure, "P", isBox); + writer.attachDofData(delp, "delp", isBox); + if (velocityOutput.enableOutput()) + { + writer.attachDofData(*velocity, "velocity", isBox, dim); + } + char nameMoleFraction0[42], nameMoleFraction1[42]; + snprintf(nameMoleFraction0, 42, "x_%s", FluidSystem::componentName(0)); + snprintf(nameMoleFraction1, 42, "x_%s", FluidSystem::componentName(1)); + writer.attachDofData(moleFraction0, nameMoleFraction0, isBox); + writer.attachDofData(moleFraction1, nameMoleFraction1, isBox); + + char nameMassFraction0[42], nameMassFraction1[42]; + snprintf(nameMassFraction0, 42, "X_%s", FluidSystem::componentName(0)); + snprintf(nameMassFraction1, 42, "X_%s", FluidSystem::componentName(1)); + writer.attachDofData(massFraction0, nameMassFraction0, isBox); + writer.attachDofData(massFraction1, nameMassFraction1, isBox); + writer.attachDofData(rho, "rho", isBox); + writer.attachDofData(mu, "mu", isBox); + writer.attachCellData(rank, "process rank"); + } +}; +} + +#include "propertydefaults.hh" + +#endif diff --git a/dumux/porousmediumflow/1p2c/implicit/properties.hh b/dumux/porousmediumflow/1p2c/implicit/properties.hh new file mode 100644 index 0000000000..7736c97a54 --- /dev/null +++ b/dumux/porousmediumflow/1p2c/implicit/properties.hh @@ -0,0 +1,81 @@ +// -*- 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 OnePTwoCModel + * \file + * + * \brief Defines the properties required for the single-phase, + * two-component fully implicit model. + */ + +#ifndef DUMUX_1P2C_PROPERTIES_HH +#define DUMUX_1P2C_PROPERTIES_HH + + +#include <dumux/implicit/box/properties.hh> +#include <dumux/implicit/cellcentered/properties.hh> +#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> + +namespace Dumux +{ +// \{ +namespace Properties +{ + +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tags for the implicit isothermal one-phase two-component problems +NEW_TYPE_TAG(OnePTwoC); +NEW_TYPE_TAG(BoxOnePTwoC, INHERITS_FROM(BoxModel, OnePTwoC)); +NEW_TYPE_TAG(CCOnePTwoC, INHERITS_FROM(CCModel, OnePTwoC)); + +//! The type tags for the corresponding non-isothermal problems +NEW_TYPE_TAG(OnePTwoCNI, INHERITS_FROM(OnePTwoC, NonIsothermal)); +NEW_TYPE_TAG(BoxOnePTwoCNI, INHERITS_FROM(BoxModel, OnePTwoCNI)); +NEW_TYPE_TAG(CCOnePTwoCNI, INHERITS_FROM(CCModel, OnePTwoCNI)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system +NEW_PROP_TAG(PhaseIdx); //!< A phase index in to allow that a two-phase fluidsystem is used +NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system +NEW_PROP_TAG(Indices); //!< Enumerations for the model +NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters +NEW_PROP_TAG(EffectiveDiffusivityModel); //!< The employed model for the computation of the effective diffusivity +NEW_PROP_TAG(FluidSystem); //!< Type of the multi-component relations +NEW_PROP_TAG(FluidState); //!< Type of the fluid state to be used +NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The default value of the upwind weight +NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation +NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem +NEW_PROP_TAG(UseMoles); //!< Defines whether mole (true) or mass (false) fractions are used +NEW_PROP_TAG(Scaling); //!< Defines Scaling of the model +NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient +NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output + +} +// \} +} + +#endif diff --git a/dumux/porousmediumflow/1p2c/implicit/propertydefaults.hh b/dumux/porousmediumflow/1p2c/implicit/propertydefaults.hh new file mode 100644 index 0000000000..cd9de92b12 --- /dev/null +++ b/dumux/porousmediumflow/1p2c/implicit/propertydefaults.hh @@ -0,0 +1,158 @@ +// -*- 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 OnePTwoCModel + * \file + * + * \brief Defines some default values for the properties of the the + * single-phase, two-component fully implicit model. + */ + +#ifndef DUMUX_1P2C_PROPERTY_DEFAULTS_HH +#define DUMUX_1P2C_PROPERTY_DEFAULTS_HH + +#include "properties.hh" +#include "model.hh" +#include "localresidual.hh" +#include "volumevariables.hh" +#include "fluxvariables.hh" +#include "indices.hh" + +#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> +#include <dumux/material/spatialparams/implicitspatialparams1p.hh> +#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> +#include <dumux/material/fluidmatrixinteractions/1p/thermalconductivityaverage.hh> +#include <dumux/material/fluidstates/compositionalfluidstate.hh> + +namespace Dumux +{ +// \{ +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Property values +////////////////////////////////////////////////////////////////// + + +SET_INT_PROP(OnePTwoC, NumEq, 2); //!< set the number of equations to 2 +SET_INT_PROP(OnePTwoC, NumPhases, 1); //!< The number of phases in the 1p2c model is 1 +SET_INT_PROP(OnePTwoC, NumComponents, 2); //!< The number of components in the 1p2c model is 2 +SET_SCALAR_PROP(OnePTwoC, Scaling, 1); //!< Scaling of the model is set to 1 by default +SET_BOOL_PROP(OnePTwoC, UseMoles, true); //!< Define that mole fractions are used in the balance equations + +//! Use the 1p2c local residual function for the 1p2c model +SET_TYPE_PROP(OnePTwoC, LocalResidual, OnePTwoCLocalResidual<TypeTag>); + +//! define the model +SET_TYPE_PROP(OnePTwoC, Model, OnePTwoCModel<TypeTag>); + +//! define the VolumeVariables +SET_TYPE_PROP(OnePTwoC, VolumeVariables, OnePTwoCVolumeVariables<TypeTag>); + +//! define the FluxVariables +SET_TYPE_PROP(OnePTwoC, FluxVariables, OnePTwoCFluxVariables<TypeTag>); + +/*! + * \brief The fluid state which is used by the volume variables to + * store the thermodynamic state. This should be chosen + * appropriately for the model ((non-)isothermal, equilibrium, ...). + * This can be done in the problem. + */ +SET_PROP(OnePTwoC, 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 weight to 1.0, i.e. fully upwind +SET_SCALAR_PROP(OnePTwoC, ImplicitMassUpwindWeight, 1.0); + +//! weight for the upwind mobility in the velocity calculation +SET_SCALAR_PROP(OnePTwoC, ImplicitMobilityUpwindWeight, 1.0); + +//! Set the indices used by the 1p2c model +SET_TYPE_PROP(OnePTwoC, Indices, OnePTwoCIndices<TypeTag>); +//! The spatial parameters to be employed. +//! Use ImplicitSpatialParamsOneP by default. +SET_TYPE_PROP(OnePTwoC, SpatialParams, ImplicitSpatialParamsOneP<TypeTag>); + +//! The model after Millington (1961) is used for the effective diffusivity +SET_PROP(OnePTwoC, EffectiveDiffusivityModel) +{ private : + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + public: + typedef DiffusivityMillingtonQuirk<Scalar> type; +}; + +//! Set the phaseIndex per default to zero (important for two-phase fluidsystems). +SET_INT_PROP(OnePTwoC, PhaseIdx, 0); + +// disable velocity output by default +SET_BOOL_PROP(OnePTwoC, VtkAddVelocity, false); + +// enable gravity by default +SET_BOOL_PROP(OnePTwoC, ProblemEnableGravity, true); + +//! default value for the forchheimer coefficient +// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. +// Actually the Forchheimer coefficient is also a function of the dimensions of the +// porous medium. Taking it as a constant is only a first approximation +// (Nield, Bejan, Convection in porous media, 2006, p. 10) +SET_SCALAR_PROP(OnePTwoC, SpatialParamsForchCoeff, 0.55); + +//! average is used as default model to compute the effective thermal heat conductivity +SET_PROP(OnePTwoCNI, ThermalConductivityModel) +{ private : + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + public: + typedef ThermalConductivityAverage<Scalar> type; +}; + +////////////////////////////////////////////////////////////////// +// Property values for isothermal model required for the general non-isothermal model +////////////////////////////////////////////////////////////////// + +// set isothermal Model +SET_TYPE_PROP(OnePTwoCNI, IsothermalModel, OnePTwoCModel<TypeTag>); + +// set isothermal FluxVariables +SET_TYPE_PROP(OnePTwoCNI, IsothermalFluxVariables, OnePTwoCFluxVariables<TypeTag>); + +//set isothermal VolumeVariables +SET_TYPE_PROP(OnePTwoCNI, IsothermalVolumeVariables, OnePTwoCVolumeVariables<TypeTag>); + +//set isothermal LocalResidual +SET_TYPE_PROP(OnePTwoCNI, IsothermalLocalResidual, OnePTwoCLocalResidual<TypeTag>); + +//set isothermal Indices +SET_TYPE_PROP(OnePTwoCNI, IsothermalIndices, OnePTwoCIndices<TypeTag>); + +//set isothermal NumEq +SET_INT_PROP(OnePTwoCNI, IsothermalNumEq, 2); + + +} +// \} +} + +#endif diff --git a/dumux/porousmediumflow/1p2c/implicit/volumevariables.hh b/dumux/porousmediumflow/1p2c/implicit/volumevariables.hh new file mode 100644 index 0000000000..1e73c90a42 --- /dev/null +++ b/dumux/porousmediumflow/1p2c/implicit/volumevariables.hh @@ -0,0 +1,287 @@ +// -*- 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 box + * model defined on a vertex. + */ +#ifndef DUMUX_1P2C_VOLUME_VARIABLES_HH +#define DUMUX_1P2C_VOLUME_VARIABLES_HH + +#include <dumux/implicit/volumevariables.hh> + +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup OnePTwoCModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are constant within a + * finite volume in the single-phase, two-component model. + */ +template <class TypeTag> +class OnePTwoCVolumeVariables : 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, FluidSystem) FluidSystem; + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + phaseIdx = Indices::phaseIdx, + phaseCompIdx = Indices::phaseCompIdx, + transportCompIdx = Indices::transportCompIdx + }; + //indices of primary variables + enum{ + pressureIdx = Indices::pressureIdx, + massOrMoleFracIdx = Indices::massOrMoleFracIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + enum { dim = GridView::dimension }; + enum { dimWorld = GridView::dimensionworld }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar,dim> DimVector; + typedef Dune::FieldVector<Scalar,dimWorld> GlobalPosition; + +public: + + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; + + /*! + * \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); + + //calculate all secondary variables from the primary variables and store results in fluidstate + completeFluidState(priVars, problem, element, fvGeometry, scvIdx, fluidState_); + + porosity_ = problem.spatialParams().porosity(element, fvGeometry, scvIdx); + + dispersivity_ = problem.spatialParams().dispersivity(element, fvGeometry, scvIdx); + + // Second instance of a parameter cache. + // Could be avoided if diffusion coefficients also + // became part of the fluid state. + typename FluidSystem::ParameterCache paramCache; + paramCache.updatePhase(fluidState_, phaseIdx); + + diffCoeff_ = FluidSystem::binaryDiffusionCoefficient(fluidState_, + paramCache, + phaseIdx, + phaseCompIdx, + transportCompIdx); + + Valgrind::CheckDefined(porosity_); + Valgrind::CheckDefined(dispersivity_); + Valgrind::CheckDefined(diffCoeff_); + + // energy related quantities not contained in the fluid state + asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol); + } + + /*! + * \copydoc ImplicitModel::completeFluidState + */ + static void completeFluidState(const PrimaryVariables& priVars, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const int scvIdx, + FluidState& fluidState) + { + Scalar t = Implementation::temperature_(priVars, problem, element, + fvGeometry, scvIdx); + fluidState.setTemperature(t); + fluidState.setSaturation(phaseIdx, 1.); + + fluidState.setPressure(phaseIdx, priVars[pressureIdx]); + + if(useMoles) + { + fluidState.setMoleFraction(phaseIdx, phaseCompIdx, 1 - priVars[massOrMoleFracIdx]); + fluidState.setMoleFraction(phaseIdx, transportCompIdx, priVars[massOrMoleFracIdx]); + } + else + { + // setMassFraction() has only to be called 1-numComponents times + fluidState.setMassFraction(phaseIdx, transportCompIdx, priVars[massOrMoleFracIdx]); + } + + typename FluidSystem::ParameterCache paramCache; + paramCache.updatePhase(fluidState, phaseIdx); + + Scalar value; + value = FluidSystem::density(fluidState, paramCache, phaseIdx); + fluidState.setDensity(phaseIdx, value); + value = FluidSystem::viscosity(fluidState, paramCache, phaseIdx); + fluidState.setViscosity(phaseIdx, value); + + // compute and set the enthalpy + Scalar h = Implementation::enthalpy_(fluidState, paramCache, phaseIdx); + fluidState.setEnthalpy(phaseIdx, h); + } + + /*! + * \brief Return the fluid configuration at the given primary + * variables + */ + const FluidState &fluidState() const + { return fluidState_; } + + /*! + * \brief Return density \f$\mathrm{[kg/m^3]}\f$ the of the fluid phase. + */ + Scalar density() const + { return fluidState_.density(phaseIdx); } + + /*! + * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ the of the fluid phase. + */ + Scalar molarDensity() const + { return fluidState_.molarDensity(phaseIdx);} + + /*! + * \brief Return mole fraction \f$\mathrm{[mol/mol]}\f$ of a component in the phase. + * + * \param compIdx The index of the component + */ + Scalar moleFraction(int compIdx) const + { return fluidState_.moleFraction(phaseIdx, (compIdx==0)?phaseCompIdx:transportCompIdx); } + + /*! + * \brief Return mass fraction \f$\mathrm{[kg/kg]}\f$ of a component in the phase. + * + * \param compIdx The index of the component + */ + Scalar massFraction(int compIdx) const + { return fluidState_.massFraction(phaseIdx, (compIdx==0)?phaseCompIdx:transportCompIdx); } + + /*! + * \brief Return concentration \f$\mathrm{[mol/m^3]}\f$ of a component in the phase. + * + * \param compIdx The index of the component + */ + Scalar molarity(int compIdx) const + { return fluidState_.molarity(phaseIdx, (compIdx==0)?phaseCompIdx:transportCompIdx); } + + /*! + * \brief Return the effective pressure \f$\mathrm{[Pa]}\f$ of a given phase within + * the control volume. + */ + Scalar pressure() const + { return fluidState_.pressure(phaseIdx); } + + /*! + * \brief Return the binary diffusion coefficient \f$\mathrm{[m^2/s]}\f$ in the fluid. + */ + Scalar diffCoeff() const + { return diffCoeff_; } + + /*! + * \brief Returns the dispersivity of the fluid's streamlines. + */ + const GlobalPosition &dispersivity() const + { return dispersivity_; } + + /*! + * \brief Return temperature \f$\mathrm{[K]}\f$ inside the sub-control volume. + * + * Note that we assume thermodynamic equilibrium, i.e. the + * temperature of the rock matrix and of all fluid phases are + * identical. + */ + Scalar temperature() const + { return fluidState_.temperature(phaseIdx); } + + /*! + * \brief Return the dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of a given phase + * within the control volume. + */ + Scalar viscosity() const + { return fluidState_.viscosity(phaseIdx); } + + /*! + * \brief Return the average porosity \f$\mathrm{[-]}\f$ within the control volume. + */ + Scalar porosity() const + { return porosity_; } + +protected: + static Scalar temperature_(const PrimaryVariables &priVars, + const Problem& problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) + { + return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); + } + + template<class ParameterCache> + static Scalar enthalpy_(const FluidState& fluidState, + const ParameterCache& paramCache, + const int phaseIdx) + { + return 0; + } + + /*! + * \brief Called by update() to compute the energy related quantities. + */ + void updateEnergy_(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx, + const bool isOldSol) + { } + + Scalar porosity_; //!< Effective porosity within the control volume + GlobalPosition dispersivity_; + Scalar diffCoeff_; + FluidState fluidState_; + +private: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } +}; + +}// end namespace + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/fluxvariables.hh b/dumux/porousmediumflow/2p2c/implicit/fluxvariables.hh new file mode 100644 index 0000000000..73224c6306 --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/fluxvariables.hh @@ -0,0 +1,255 @@ +// -*- 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 Contains the data which is required to calculate + * all fluxes of components over a face of a finite volume for + * the two-phase two-component model fully implicit model. + */ +#ifndef DUMUX_2P2C_FLUX_VARIABLES_HH +#define DUMUX_2P2C_FLUX_VARIABLES_HH + +#include <dumux/common/math.hh> +#include <dumux/common/spline.hh> + +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitFluxVariables + * \brief Contains the data which is required to calculate + * all fluxes of components over a face of a finite volume for + * the two-phase two-component model fully implicit model. + * + * This means pressure and concentration gradients, phase densities at + * the integration point, etc. + */ +template <class TypeTag> +class TwoPTwoCFluxVariables : public GET_PROP_TYPE(TypeTag, BaseFluxVariables) +{ + typedef typename GET_PROP_TYPE(TypeTag, BaseFluxVariables) BaseFluxVariables; + 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; + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + enum { dim = GridView::dimension }; + enum { dimWorld = GridView::dimensionworld} ; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + + 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 sub-control-volume face + * \param elemVolVars The volume variables of the current element + * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face + */ + TwoPTwoCFluxVariables(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : BaseFluxVariables(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) + { + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + density_[phaseIdx] = Scalar(0); + molarDensity_[phaseIdx] = Scalar(0); + moleFractionGrad_[phaseIdx] = Scalar(0); + } + + calculateValues_(problem, element, elemVolVars); + } + + protected: + void calculateValues_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + // calculate densities at the integration points of the face + GlobalPosition tmp(0.0); + for (unsigned int idx = 0; + idx < this->face().numFap; + idx++) // loop over adjacent vertices + { + // index for the element volume variables + int volVarsIdx = this->face().fapIndices[idx]; + + for (int phaseIdx = 0; phaseIdx < numPhases; phaseIdx++) + { + density_[phaseIdx] += elemVolVars[volVarsIdx].density(phaseIdx)* + this->face().shapeValue[idx]; + molarDensity_[phaseIdx] += elemVolVars[volVarsIdx].molarDensity(phaseIdx)* + this->face().shapeValue[idx]; + } + } + + calculateGradients_(problem, element, elemVolVars); + calculatePorousDiffCoeff_(problem, element, elemVolVars); + } + + void calculateGradients_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + // calculate gradients + GlobalPosition tmp(0.0); + for (unsigned int idx = 0; + idx < this->face().numFap; + idx++) // loop over adjacent vertices + { + // FE gradient at vertex idx + const GlobalPosition &feGrad = this->face().grad[idx]; + + // index for the element volume variables + int volVarsIdx = this->face().fapIndices[idx]; + + // the mole fraction gradient of the wetting phase + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, nCompIdx); + moleFractionGrad_[wPhaseIdx] += tmp; + + // the mole fraction gradient of the non-wetting phase + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, wCompIdx); + moleFractionGrad_[nPhaseIdx] += tmp; + } + } + + Scalar rhoFactor_(int phaseIdx, int scvIdx, const ElementVolumeVariables &vDat) + { + static const Scalar eps = 1e-2; + const Scalar sat = vDat[scvIdx].density(phaseIdx); + if (sat > eps) + return 0.5; + if (sat <= 0) + return 0; + + static const Dumux::Spline<Scalar> sp(0, eps, // x0, x1 + 0, 0.5, // y0, y1 + 0, 0); // m0, m1 + return sp.eval(sat); + } + + void calculatePorousDiffCoeff_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + const VolumeVariables &volVarsI = elemVolVars[this->face().i]; + const VolumeVariables &volVarsJ = elemVolVars[this->face().j]; + + // the effective diffusion coefficients at vertex i and j + Scalar diffCoeffI; + Scalar diffCoeffJ; + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // make sure to only calculate diffusion coefficients + // for phases which exist in both finite volumes + if (volVarsI.saturation(phaseIdx) <= 0 || volVarsJ.saturation(phaseIdx) <= 0) + { + porousDiffCoeff_[phaseIdx] = 0.0; + continue; + } + + diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), + volVarsI.saturation(phaseIdx), + volVarsI.diffCoeff(phaseIdx)); + + diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), + volVarsJ.saturation(phaseIdx), + volVarsJ.diffCoeff(phaseIdx)); + + // -> harmonic mean + porousDiffCoeff_[phaseIdx] = harmonicMean(diffCoeffI, diffCoeffJ); + } + } + + public: + /*! + * \brief Returns the effective diffusion coefficient \f$\mathrm{[m^2/s]}\f$ + * for each fluid phase in the porous medium. + * + * \param phaseIdx The phase index + */ + Scalar porousDiffCoeff(int phaseIdx) const + { return porousDiffCoeff_[phaseIdx]; }; + + /*! + * \brief Returns the density \f$\mathrm{[kg/m^3]}\f$ of a phase. + * + * \param phaseIdx The phase index + */ + Scalar density(int phaseIdx) const + { return density_[phaseIdx]; } + + /*! + * \brief Returns the molar density \f$\mathrm{[mol/m^3]}\f$ of a phase. + * + * \param phaseIdx The phase index + */ + Scalar molarDensity(int phaseIdx) const + { return molarDensity_[phaseIdx]; } + + /*! + * \brief Returns the mole fraction gradient \f$\mathrm{[1/m]}\f$ + * of the dissolved component in a phase. + * + * \param phaseIdx The phase index + */ + const GlobalPosition &moleFractionGrad(int phaseIdx) const + { return moleFractionGrad_[phaseIdx]; }; + + protected: + // mole fraction gradients + GlobalPosition moleFractionGrad_[numPhases]; + + // density of each face at the integration point + Scalar density_[numPhases], molarDensity_[numPhases]; + + // the diffusion coefficient for the porous medium + Scalar porousDiffCoeff_[numPhases]; +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/indices.hh b/dumux/porousmediumflow/2p2c/implicit/indices.hh new file mode 100644 index 0000000000..a3518b278f --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/indices.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 Defines the indices required for the two-phase two-component + * fully implicit model. + */ +#ifndef DUMUX_2P2C_INDICES_HH +#define DUMUX_2P2C_INDICES_HH + +#include "properties.hh" + +namespace Dumux +{ +// \{ + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitIndices + * \brief Enumerates the formulations which the two-phase two-component model accepts. + */ +struct TwoPTwoCFormulation +{ + static const int pwsn = 0; //!< pw and sn as primary variables + static const int pnsw = 1; //!< pn and sw as primary variables +}; + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitIndices + * \brief The indices for the isothermal two-phase two-component model. + * + * \tparam formulation The formulation, either pwsn or pnsw. + * \tparam PVOffset The first index in a primary variable vector. + */ +template <class TypeTag, + int formulation = TwoPTwoCFormulation::pwsn, + int PVOffset = 0> +class TwoPTwoCIndices +{ + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + +public: + // Phase indices + static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< Index of the wetting phase + static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< Index of the non-wetting phase + + // Component indices + static const int wCompIdx = FluidSystem::wCompIdx; //!< Index of the primary component of the wetting phase + static const int nCompIdx = FluidSystem::nCompIdx; //!< Index of the primary component of the non-wetting phase + + // present phases (-> 'pseudo' primary variable) + static const int wPhaseOnly = 1; //!< Only the wetting phase is present + static const int nPhaseOnly = 0; //!< Only the non-wetting phase is present + static const int bothPhases = 2; //!< Both phases are present + + // Primary variable indices + //! Index for wetting/non-wetting phase pressure (depending on the formulation) in a solution vector + static const int pressureIdx = PVOffset + 0; + //! Index of either the saturation or the mass fraction of the non-wetting/wetting phase + static const int switchIdx = PVOffset + 1; + + //! Index for wetting phase pressure in a solution vector + static const int pwIdx = pressureIdx; + //! Index of either the saturation of the non-wetting phase or the mass fraction secondary component in the only phase + static const int snOrXIdx = switchIdx; + + // equation indices + //! Index of the mass conservation equation for the first component + static const int conti0EqIdx = PVOffset; + //! Index of the mass conservation equation for the primary component of the wetting phase + static const int contiWEqIdx = conti0EqIdx + wCompIdx; + //! Index of the mass conservation equation for the primary component of the non-wetting phase + static const int contiNEqIdx = conti0EqIdx + nCompIdx; +}; + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitIndices + * \brief The indices for the isothermal two-phase two-component model in the pn-sw + * formulation. + * + * \tparam PVOffset The first index in a primary variable vector. + */ +template <class TypeTag, int PVOffset> +class TwoPTwoCIndices<TypeTag, TwoPTwoCFormulation::pnsw, PVOffset> +{ + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + +public: + // Phase indices + static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< Index of the wetting phase + static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< Index of the non-wetting phase + + // Component indices + static const int wCompIdx = FluidSystem::wCompIdx; //!< Index of the primary component of the wetting phase + static const int nCompIdx = FluidSystem::nCompIdx; //!< Index of the primary component of the non-wetting phase + + // present phases (-> 'pseudo' primary variable) + static const int wPhaseOnly = 1; //!< Only the wetting phase is present + static const int nPhaseOnly = 2; //!< Only the non-wetting phase is present + static const int bothPhases = 3; //!< Both phases are present + + // Primary variable indices + //! Index for wetting/non-wetting phase pressure (depending on the formulation) in a solution vector + static const int pressureIdx = PVOffset + 0; + //! Index of either the saturation or the mass fraction of the non-wetting/wetting phase + static const int switchIdx = PVOffset + 1; + + //! Index for non-wetting phase pressure in a solution vector + static const int pnIdx = pressureIdx; + //! Index of either the saturation of the liquid phase or the mass fraction of the secondary component in the only phase + static const int swOrXIdx = switchIdx; + + // Equation indices + //! Index of the mass conservation equation for the first component + static const int conti0EqIdx = PVOffset; + //! Index of the mass conservation equation for the primary component of the wetting phase + static const int contiWEqIdx = conti0EqIdx + wCompIdx; + //! Index of the mass conservation equation for the primary component of the non-wetting phase + static const int contiNEqIdx = conti0EqIdx + nCompIdx; +}; + +// \} + +} + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/localresidual.hh b/dumux/porousmediumflow/2p2c/implicit/localresidual.hh new file mode 100644 index 0000000000..bd059ad725 --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/localresidual.hh @@ -0,0 +1,507 @@ +// -*- 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 Jacobian matrix for problems + * using the two-phase two-component fully implicit model. + */ + +#ifndef DUMUX_2P2C_LOCAL_RESIDUAL_BASE_HH +#define DUMUX_2P2C_LOCAL_RESIDUAL_BASE_HH + +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitLocalResidual + * \brief Element-wise calculation of the Jacobian matrix for problems + * using the two-phase two-component fully implicit model. + * + * This class is used to fill the gaps in ImplicitLocalResidual for the + * two-phase two-component flow. + */ +template<class TypeTag> +class TwoPTwoCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) +{ + protected: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + enum + { + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents) + }; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum + { + contiWEqIdx = Indices::contiWEqIdx, + contiNEqIdx = Indices::contiNEqIdx, + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + + static constexpr unsigned int replaceCompEqIdx = + GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx); + + //! Property that defines whether mole or mass fractions are used + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + + public: + /*! + * \brief Constructor + * + * Sets the mass upwind weight. + */ + TwoPTwoCLocalResidual() + { + // 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 storage term of the current solution in a + * single phase. + * + * \param element The element + * \param phaseIdx The index of the fluid phase + */ + void evalPhaseStorage(const Element &element, const int phaseIdx) + { + FVElementGeometry fvGeometry; + fvGeometry.update(this->gridView_(), element); + ElementBoundaryTypes bcTypes; + bcTypes.update(this->problem_(), element, fvGeometry); + ElementVolumeVariables elemVolVars; + elemVolVars.update(this->problem_(), element, fvGeometry, false); + + this->storageTerm_.resize(fvGeometry.numScv); + this->storageTerm_ = 0; + + this->elemPtr_ = &element; + this->fvElemGeomPtr_ = &fvGeometry; + this->bcTypesPtr_ = &bcTypes; + this->prevVolVarsPtr_ = 0; + this->curVolVarsPtr_ = &elemVolVars; + evalPhaseStorage_(phaseIdx); + } + + /*! + * \brief Evaluate the amount of all conservation quantities + * (e.g. phase mass) within a sub-control volume. + * + * \param storage The mass of the component within the sub-control volume + * \param scvIdx The sub-control-volume index + * \param usePrevSol Based on usePrevSol solution of current or previous time step is used + * + * The result should be averaged over the volume (e.g. phase mass + * inside a sub-control volume divided by the volume) + */ + void computeStorage(PrimaryVariables &storage, const 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]; + + // compute storage term of all components within all phases + storage = 0; + if(useMoles) // mole-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx); + } + // this is only processed if one component mass balance equation + // is replaced by the total mass balance equation + if (replaceCompEqIdx < numComponents) + storage[replaceCompEqIdx] += + volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx); + } + storage *= volVars.porosity(); + } + else // mass-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.density(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.massFraction(phaseIdx, compIdx); + } + // this is only processed if one component mass balance equation + // is replaced by the total mass balance equation + if (replaceCompEqIdx < numComponents) + storage[replaceCompEqIdx] += + volVars.density(phaseIdx) + * volVars.saturation(phaseIdx); + } + storage *= volVars.porosity(); + } + } + + /*! + * \brief Evaluates the total flux of all conservation quantities + * over a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fIdx The index of the sub-control-volume face + * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face + */ + void computeFlux(PrimaryVariables &flux, const int fIdx, bool onBoundary=false) const + { + FluxVariables fluxVars(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_(), + onBoundary); + + flux = 0; + asImp_()->computeAdvectiveFlux(flux, fluxVars); + Valgrind::CheckDefined(flux); + asImp_()->computeDiffusiveFlux(flux, fluxVars); + Valgrind::CheckDefined(flux); + } + + /*! + * \brief Evaluates the advective mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current sub-control-volume face + */ + void computeAdvectiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + { + //////// + // advective fluxes of all components in all phases + //////// + + if(useMoles) // mole-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // 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)); + + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + // add advective flux of current component in current + // phase + if (massUpwindWeight_ > 0.0) + // upstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.molarDensity(phaseIdx) + * up.moleFraction(phaseIdx, compIdx); + if (massUpwindWeight_ < 1.0) + // downstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.molarDensity(phaseIdx) + * dn.moleFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(up.moleFraction(phaseIdx, compIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.moleFraction(phaseIdx, compIdx)); + } + // flux of the total mass balance; + // this is only processed if one component mass balance equation + // is replaced by a total mass balance equation + if (replaceCompEqIdx < numComponents) + { + // upstream vertex + if (massUpwindWeight_ > 0.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.molarDensity(phaseIdx); + // downstream vertex + if (massUpwindWeight_ < 1.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.molarDensity(phaseIdx); + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + + } + + } + } + else // mass-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // data attached to upstream and downstream vertices + // of the current phase + const VolumeVariables &up = + this->curVolVars_(fluxVars.upstreamIdx(phaseIdx)); + const VolumeVariables &dn = + this->curVolVars_(fluxVars.downstreamIdx(phaseIdx)); + + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + // add advective flux of current component in current + // phase + if (massUpwindWeight_ > 0.0) + // upstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.density(phaseIdx) + * up.massFraction(phaseIdx, compIdx); + if (massUpwindWeight_ < 1.0) + // downstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.density(phaseIdx) + * dn.massFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.density(phaseIdx)); + Valgrind::CheckDefined(up.massFraction(phaseIdx, compIdx)); + Valgrind::CheckDefined(dn.density(phaseIdx)); + Valgrind::CheckDefined(dn.massFraction(phaseIdx, compIdx)); + } + // flux of the total mass balance; + // this is only processed if one component mass balance equation + // is replaced by a total mass balance equation + if (replaceCompEqIdx < numComponents) + { + // upstream vertex + if (massUpwindWeight_ > 0.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.density(phaseIdx); + // downstream vertex + if (massUpwindWeight_ < 1.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.density(phaseIdx); + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.density(phaseIdx)); + Valgrind::CheckDefined(dn.density(phaseIdx)); + + } + + } + } + } + + /*! + * \brief Evaluates the diffusive mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The 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 + + { + if(useMoles) // mole-fraction formulation + { + // add diffusive flux of gas component in liquid phase + Scalar tmp = - (fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal); + tmp *= + fluxVars.porousDiffCoeff(wPhaseIdx) * + fluxVars.molarDensity(wPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] += tmp; + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] -= tmp; + + // add diffusive flux of liquid component in non-wetting phase + tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal); + tmp *= + fluxVars.porousDiffCoeff(nPhaseIdx) * + fluxVars.molarDensity(nPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] += tmp; + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] -= tmp; + } + else // mass-fraction formulation + { + // add diffusive flux of gas component in liquid phase + Scalar tmp = - (fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal); + tmp *= + fluxVars.porousDiffCoeff(wPhaseIdx) * + fluxVars.molarDensity(wPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] += tmp * FluidSystem::molarMass(nCompIdx); + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] -= tmp * FluidSystem::molarMass(wCompIdx); + + // add diffusive flux of liquid component in non-wetting phase + tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal); + tmp *= + fluxVars.porousDiffCoeff(nPhaseIdx) * + fluxVars.molarDensity(nPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] += tmp * FluidSystem::molarMass(wCompIdx); + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] -= tmp * FluidSystem::molarMass(nCompIdx); + } + } + + protected: + void evalPhaseStorage_(const int phaseIdx) + { + if(useMoles) // mole-fraction formulation + { + // evaluate the storage terms of a single phase + for (int i=0; i < this->fvGeometry_().numScv; i++) { + PrimaryVariables &storage = this->storageTerm_[i]; + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[i]; + + // compute storage term of all components within all phases + storage = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx); + } + + storage *= volVars.porosity(); + storage *= this->fvGeometry_().subContVol[i].volume; + } + } + else // mass-fraction formulation + { + // evaluate the storage terms of a single phase + for (int i=0; i < this->fvGeometry_().numScv; i++) { + PrimaryVariables &storage = this->storageTerm_[i]; + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[i]; + + // compute storage term of all components within all phases + storage = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.density(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.massFraction(phaseIdx, compIdx); + } + + storage *= volVars.porosity(); + storage *= this->fvGeometry_().subContVol[i].volume; + } + } + } + + /*! + * \brief Returns the equation index of the first mass-balance equation + * of the component (used for loops) + * + * Returns the equation index of the first mass-balance equation + * of the component (used for loops) if one component mass balance + * is replaced by the total mass balance, this is the index + * of the remaining component mass-balance equation. + */ + unsigned int contiCompIdx1_() const { + switch (replaceCompEqIdx) + { + case contiWEqIdx: return contiNEqIdx; + case contiNEqIdx: return contiWEqIdx; + default: return 0; + } + } + + /*! + * \brief Returns the equation index of the second mass balance + * of the component (used for loops) + * + * Returns the equation index of the second mass balance + * of the component (used for loops) + * if one component mass balance is replaced by the total mass balance + * (replaceCompEqIdx < 2), this index is the same as contiCompIdx1(). + */ + unsigned int contiCompIdx2_() const { + switch (replaceCompEqIdx) + { + case contiWEqIdx: return contiNEqIdx; + case contiNEqIdx: return contiWEqIdx; + default: return numComponents-1; + } + } + + Implementation *asImp_() + { return static_cast<Implementation *> (this); } + const Implementation *asImp_() const + { return static_cast<const Implementation *> (this); } + + private: + Scalar massUpwindWeight_; +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/model.hh b/dumux/porousmediumflow/2p2c/implicit/model.hh new file mode 100644 index 0000000000..d298e467b3 --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/model.hh @@ -0,0 +1,725 @@ +// -*- 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 two-component fully implicit model. + */ +#ifndef DUMUX_2P2C_MODEL_HH +#define DUMUX_2P2C_MODEL_HH + +#include "properties.hh" +#include "indices.hh" +#include <dumux/porousmediumflow/implicit/velocityoutput.hh> + +namespace Dumux +{ +/*! + * \ingroup TwoPTwoCModel + * \brief Adaption of the fully implicit scheme to the + * two-phase two-component fully implicit model. + * + * This model implements two-phase two-component flow of two compressible and + * partially miscible fluids \f$\alpha \in \{ w, n \}\f$ composed of the two components + * \f$\kappa \in \{ w, a \}\f$. The standard multiphase Darcy + * approach is used as the equation for the conservation of momentum: + * \f[ + v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mathbf{K} + \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) + * \f] + * + * By inserting this into the equations for the conservation of the + * components, one gets one transport equation for each component + * \f{eqnarray*} + && \phi \frac{\partial (\sum_\alpha \varrho_\alpha \frac{M^\kappa}{M_\alpha} x_\alpha^\kappa S_\alpha )} + {\partial t} + - \sum_\alpha \text{div} \left\{ \varrho_\alpha \frac{M^\kappa}{M_\alpha} x_\alpha^\kappa + \frac{k_{r\alpha}}{\mu_\alpha} \mathbf{K} + (\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g}) \right\} + \nonumber \\ \nonumber \\ + &-& \sum_\alpha \text{div} \left\{ D_{\alpha,\text{pm}}^\kappa \varrho_{\alpha} \frac{M^\kappa}{M_\alpha} + \textbf{grad} x^\kappa_{\alpha} \right\} + - \sum_\alpha q_\alpha^\kappa = 0 \qquad \kappa \in \{w, a\} \, , + \alpha \in \{w, g\} + \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. + * + * By using constitutive relations for the capillary pressure \f$p_c = + * p_n - p_w\f$ and relative permeability \f$k_{r\alpha}\f$ and taking + * advantage of the fact that \f$S_w + S_n = 1\f$ and \f$x^\kappa_w + x^\kappa_n = 1\f$, the number of + * unknowns can be reduced to two. + * The used primary variables are, like in the two-phase model, either \f$p_w\f$ and \f$S_n\f$ + * or \f$p_n\f$ and \f$S_w\f$. The formulation which ought to be used can be + * specified by setting the <tt>Formulation</tt> property to either + * TwoPTwoCIndices::pWsN or TwoPTwoCIndices::pNsW. By + * default, the model uses \f$p_w\f$ and \f$S_n\f$. + * Moreover, the second primary variable depends on the phase state, since a + * primary variable switch is included. The phase state is stored for all nodes + * of the system. + * The model is able to use either mole or mass fractions. The property useMoles can be set to either true or false in the + * problem file. Make sure that the according units are used in the problem setup. useMoles is set to true by default. + * Following cases can be distinguished: + * <ul> + * <li> Both phases are present: The saturation is used (either \f$S_n\f$ or \f$S_w\f$, dependent on the chosen <tt>Formulation</tt>), + * as long as \f$ 0 < S_\alpha < 1\f$</li>. + * <li> Only wetting phase is present: The mole fraction of, e.g., air in the wetting phase \f$x^a_w\f$ is used, + * as long as the maximum mole fraction is not exceeded \f$(x^a_w<x^a_{w,max})\f$</li> + * <li> Only non-wetting phase is present: The mole fraction of, e.g., water in the non-wetting phase, \f$x^w_n\f$, is used, + * as long as the maximum mole fraction is not exceeded \f$(x^w_n<x^w_{n,max})\f$</li> + * </ul> + */ + +template<class TypeTag> +class TwoPTwoCModel: public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, BaseModel) ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + enum { + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents) + }; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + switchIdx = Indices::switchIdx, + + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx, + + wPhaseOnly = Indices::wPhaseOnly, + nPhaseOnly = Indices::nPhaseOnly, + bothPhases = Indices::bothPhases, + + pwsn = TwoPTwoCFormulation::pwsn, + pnsw = TwoPTwoCFormulation::pnsw, + formulation = GET_PROP_VALUE(TypeTag, Formulation) + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + enum { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + +public: + /*! + * \brief Initialize the static data with the initial solution. + * + * \param problem The problem to be solved + */ + void init(Problem &problem) + { + ParentType::init(problem); + + unsigned numDofs = this->numDofs(); + + staticDat_.resize(numDofs); + + setSwitched_(false); + + // check, if velocity output can be used (works only for cubes so far) + for (const auto& element : Dune::elements(this->gridView_())) + { + if (!isBox) // i.e. cell-centered discretization + { + int eIdxGlobal = this->dofMapper().index(element); + const GlobalPosition &globalPos = element.geometry().center(); + + // initialize phase presence + staticDat_[eIdxGlobal].phasePresence + = this->problem_().initialPhasePresence(*(this->gridView_().template begin<dim>()), + eIdxGlobal, globalPos); + staticDat_[eIdxGlobal].wasSwitched = false; + + staticDat_[eIdxGlobal].oldPhasePresence + = staticDat_[eIdxGlobal].phasePresence; + } + } + + if (isBox) // i.e. vertex-centered discretization + { + for (const auto& vertex : Dune::vertices(this->gridView_())) + { + int vIdxGlobal = this->dofMapper().index(vertex); + const GlobalPosition &globalPos = vertex.geometry().corner(0); + + // initialize phase presence + staticDat_[vIdxGlobal].phasePresence + = this->problem_().initialPhasePresence(vertex, vIdxGlobal, + globalPos); + staticDat_[vIdxGlobal].wasSwitched = false; + + staticDat_[vIdxGlobal].oldPhasePresence + = staticDat_[vIdxGlobal].phasePresence; + } + } + } + + /*! + * \brief Compute the total storage of all conservation quantities in one phase + * + * \param storage Contains the storage of each component in one phase + * \param phaseIdx The phase index + */ + void globalPhaseStorage(PrimaryVariables &storage, const int phaseIdx) + { + storage = 0; + + for (const auto& element : Dune::elements(this->gridView_())) { + if(element.partitionType() == Dune::InteriorEntity) + { + + + this->localResidual().evalPhaseStorage(element, phaseIdx); + + for (unsigned int i = 0; i < this->localResidual().storageTerm().size(); ++i) + storage += this->localResidual().storageTerm()[i]; + } + } + if (this->gridView_().comm().size() > 1) + storage = this->gridView_().comm().sum(storage); + } + + /*! + * \brief Called by the update() method if applying the Newton + * method was unsuccessful. + */ + void updateFailed() + { + ParentType::updateFailed(); + + setSwitched_(false); + resetPhasePresence_(); + } + + /*! + * \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() + { + ParentType::advanceTimeLevel(); + + // update the phase state + updateOldPhasePresence_(); + setSwitched_(false); + } + + /*! + * \brief Returns true if the primary variables were switched for + * at least one vertex after the last timestep. + */ + bool switched() const + { + return switchFlag_; + } + + /*! + * \brief Returns the phase presence of the current or the old solution of a degree of freedom. + * + * \param dofIdxGlobal The global index of the degree of freedom + * \param oldSol Based on oldSol current or previous time step is used + */ + int phasePresence(int dofIdxGlobal, bool oldSol) const + { + return oldSol ? staticDat_[dofIdxGlobal].oldPhasePresence + : staticDat_[dofIdxGlobal].phasePresence; + } + + /*! + * \brief Append all quantities of interest which can be derived + * from the solution of the current time step to the VTK + * writer. + * + * \param sol The solution vector + * \param writer The writer for multi-file VTK datasets + */ + template<class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, + MultiWriter &writer) + { + typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<double, dimWorld> > VectorField; + + // get the number of degrees of freedom + unsigned numDofs = this->numDofs(); + + // create the required scalar fields + ScalarField *sN = writer.allocateManagedBuffer(numDofs); + ScalarField *sW = writer.allocateManagedBuffer(numDofs); + ScalarField *pn = writer.allocateManagedBuffer(numDofs); + ScalarField *pw = writer.allocateManagedBuffer(numDofs); + ScalarField *pc = writer.allocateManagedBuffer(numDofs); + ScalarField *rhoW = writer.allocateManagedBuffer(numDofs); + ScalarField *rhoN = writer.allocateManagedBuffer(numDofs); + ScalarField *mobW = writer.allocateManagedBuffer(numDofs); + ScalarField *mobN = writer.allocateManagedBuffer(numDofs); + ScalarField *phasePresence = writer.allocateManagedBuffer(numDofs); + ScalarField *massFrac[numPhases][numComponents]; + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + massFrac[phaseIdx][compIdx] = writer.allocateManagedBuffer(numDofs); + ScalarField *moleFrac[numPhases][numComponents]; + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + moleFrac[phaseIdx][compIdx] = writer.allocateManagedBuffer(numDofs); + ScalarField *temperature = writer.allocateManagedBuffer(numDofs); + ScalarField *poro = writer.allocateManagedBuffer(numDofs); + VectorField *velocityN = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); + VectorField *velocityW = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); + ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + // initialize velocity fields + for (unsigned int i = 0; i < numDofs; ++i) + { + (*velocityN)[i] = Scalar(0); + (*velocityW)[i] = Scalar(0); + } + } + + unsigned numElements = this->gridView_().size(0); + ScalarField *rank = writer.allocateManagedBuffer(numElements); + + for (const auto& element : Dune::elements(this->gridView_())) + { + if(element.partitionType() == Dune::InteriorEntity) + { + int eIdx = this->elementMapper().index(element); + (*rank)[eIdx] = this->gridView_().comm().rank(); + + FVElementGeometry fvGeometry; + fvGeometry.update(this->gridView_(), element); + + ElementVolumeVariables elemVolVars; + elemVolVars.update(this->problem_(), + element, + fvGeometry, + false /* oldSol? */); + + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); + + (*sN)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx); + (*sW)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx); + (*pn)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx); + (*pw)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx); + (*pc)[dofIdxGlobal] = elemVolVars[scvIdx].capillaryPressure(); + (*rhoW)[dofIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx); + (*rhoN)[dofIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx); + (*mobW)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(wPhaseIdx); + (*mobN)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(nPhaseIdx); + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + (*massFrac[phaseIdx][compIdx])[dofIdxGlobal] + = elemVolVars[scvIdx].massFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined((*massFrac[phaseIdx][compIdx])[dofIdxGlobal][0]); + } + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + (*moleFrac[phaseIdx][compIdx])[dofIdxGlobal] + = elemVolVars[scvIdx].moleFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined((*moleFrac[phaseIdx][compIdx])[dofIdxGlobal][0]); + } + (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity(); + (*temperature)[dofIdxGlobal] = elemVolVars[scvIdx].temperature(); + (*phasePresence)[dofIdxGlobal] + = staticDat_[dofIdxGlobal].phasePresence; + } + + // velocity output + velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); + velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); + } + + } // loop over elements + + writer.attachDofData(*sN, "Sn", isBox); + writer.attachDofData(*sW, "Sw", isBox); + writer.attachDofData(*pn, "pn", isBox); + writer.attachDofData(*pw, "pw", isBox); + writer.attachDofData(*pc, "pc", isBox); + writer.attachDofData(*rhoW, "rhoW", isBox); + writer.attachDofData(*rhoN, "rhoN", isBox); + writer.attachDofData(*mobW, "mobW", isBox); + writer.attachDofData(*mobN, "mobN", isBox); + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + std::ostringstream oss; + oss << "X_" << FluidSystem::phaseName(phaseIdx) << "^" << FluidSystem::componentName(compIdx); + writer.attachDofData(*massFrac[phaseIdx][compIdx], oss.str(), isBox); + } + } + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + std::ostringstream oss; + oss << "x_" << FluidSystem::phaseName(phaseIdx) << "^" << FluidSystem::componentName(compIdx); + writer.attachDofData(*moleFrac[phaseIdx][compIdx], oss.str(), isBox); + } + } + writer.attachDofData(*poro, "porosity", isBox); + writer.attachDofData(*temperature, "temperature", isBox); + writer.attachDofData(*phasePresence, "phase presence", isBox); + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + writer.attachDofData(*velocityW, "velocityW", isBox, dim); + writer.attachDofData(*velocityN, "velocityN", isBox, dim); + } + + writer.attachCellData(*rank, "process rank"); + } + + /*! + * \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, either a vertex or an element + */ + template<class Entity> + void serializeEntity(std::ostream &outStream, const Entity &entity) + { + // write primary variables + ParentType::serializeEntity(outStream, entity); + + int dofIdxGlobal = this->dofMapper().index(entity); + + if (!outStream.good()) + DUNE_THROW(Dune::IOError, "Could not serialize entity " << dofIdxGlobal); + + outStream << staticDat_[dofIdxGlobal].phasePresence << " "; + } + + /*! + * \brief Reads the current solution from a restart file. + * + * \param inStream The input stream of one vertex from the restart file + * \param entity The entity, either a vertex or an element + */ + template<class Entity> + void deserializeEntity(std::istream &inStream, const Entity &entity) + { + // read primary variables + ParentType::deserializeEntity(inStream, entity); + + // read phase presence + int dofIdxGlobal = this->dofMapper().index(entity); + + if (!inStream.good()) + DUNE_THROW(Dune::IOError, + "Could not deserialize entity " << dofIdxGlobal); + + inStream >> staticDat_[dofIdxGlobal].phasePresence; + staticDat_[dofIdxGlobal].oldPhasePresence + = staticDat_[dofIdxGlobal].phasePresence; + + } + + /*! + * \brief Update the static data of all vertices in the grid. + * + * \param curGlobalSol The current global solution + * \param oldGlobalSol The previous global solution + */ + void updateStaticData(SolutionVector &curGlobalSol, + const SolutionVector &oldGlobalSol) + { + bool wasSwitched = false; + int succeeded; + try { + for (unsigned i = 0; i < staticDat_.size(); ++i) + staticDat_[i].visited = false; + + FVElementGeometry fvGeometry; + static VolumeVariables volVars; + for (const auto& element : Dune::elements(this->gridView_())) + { + fvGeometry.update(this->gridView_(), element); + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); + + if (staticDat_[dofIdxGlobal].visited) + continue; + + staticDat_[dofIdxGlobal].visited = true; + volVars.update(curGlobalSol[dofIdxGlobal], + this->problem_(), + element, + fvGeometry, + scvIdx, + false); + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (primaryVarSwitch_(curGlobalSol, + volVars, + dofIdxGlobal, + globalPos)) + { + this->jacobianAssembler().markDofRed(dofIdxGlobal); + wasSwitched = true; + } + } + } + succeeded = 1; + } + catch (Dumux::NumericalProblem &e) + { + std::cout << "\n" + << "Rank " << this->problem_().gridView().comm().rank() + << " caught an exception while updating the static data." << e.what() + << "\n"; + succeeded = 0; + } + //make sure that all processes succeeded. If not throw a NumericalProblem to decrease the time step size. + if (this->gridView_().comm().size() > 1) + succeeded = this->gridView_().comm().min(succeeded); + + if (!succeeded) { + DUNE_THROW(NumericalProblem, + "A process did not succeed in updating the static data."); + return; + } + + // make sure that if there was a variable switch in an + // other partition we will also set the switch flag + // for our partition. + if (this->gridView_().comm().size() > 1) + wasSwitched = this->gridView_().comm().max(wasSwitched); + + setSwitched_(wasSwitched); + } + + protected: + /*! + * \brief Data which is attached to each vertex and is not only + * stored locally. + */ + struct StaticVars + { + int phasePresence; + bool wasSwitched; + + int oldPhasePresence; + bool visited; + }; + + /*! + * \brief Resets the current phase presence of all vertices to the old one. + * + * This is done after an update failed. + */ + void resetPhasePresence_() + { + for (unsigned int idx = 0; idx < staticDat_.size(); ++idx) + { + staticDat_[idx].phasePresence + = staticDat_[idx].oldPhasePresence; + staticDat_[idx].wasSwitched = false; + } + } + + /*! + * \brief Sets the phase presence of all vertices state to the current one. + */ + void updateOldPhasePresence_() + { + for (unsigned int idx = 0; idx < staticDat_.size(); ++idx) + { + staticDat_[idx].oldPhasePresence + = staticDat_[idx].phasePresence; + staticDat_[idx].wasSwitched = false; + } + } + + /*! + * \brief Sets whether there was a primary variable switch after + * the last timestep. + */ + void setSwitched_(bool yesno) + { + switchFlag_ = yesno; + } + + /*! + * \brief Performs variable switch at a vertex, returns true if a + * variable switch was performed. + */ + bool primaryVarSwitch_(SolutionVector &globalSol, + const VolumeVariables &volVars, + int dofIdxGlobal, + const GlobalPosition &globalPos) + { + // evaluate primary variable switch + bool wouldSwitch = false; + int phasePresence = staticDat_[dofIdxGlobal].phasePresence; + int newPhasePresence = phasePresence; + + // check if a primary var switch is necessary + if (phasePresence == nPhaseOnly) + { + // calculate mole fraction in the hypothetic wetting phase + Scalar xww = volVars.moleFraction(wPhaseIdx, wCompIdx); + Scalar xwn = volVars.moleFraction(wPhaseIdx, nCompIdx); + + Scalar xwMax = 1.0; + if (xww + xwn > xwMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xwMax *= 1.02; + + // if the sum of the mole fractions is larger than + // 100%, wetting phase appears + if (xww + xwn > xwMax) + { + // wetting phase appears + std::cout << "wetting phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xww + xwn: " + << xww + xwn << std::endl; + newPhasePresence = bothPhases; + if (formulation == pnsw) + globalSol[dofIdxGlobal][switchIdx] = 0.0; + else if (formulation == pwsn) + globalSol[dofIdxGlobal][switchIdx] = 1.0; + } + } + else if (phasePresence == wPhaseOnly) + { + // calculate fractions of the partial pressures in the + // hypothetic nonwetting phase + Scalar xnw = volVars.moleFraction(nPhaseIdx, wCompIdx); + Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); + + Scalar xgMax = 1.0; + if (xnw + xnn > xgMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xgMax *= 1.02; + + // if the sum of the mole fractions is larger than + // 100%, nonwetting phase appears + if (xnw + xnn > xgMax) + { + // nonwetting phase appears + std::cout << "nonwetting phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xnw + xnn: " + << xnw + xnn << std::endl; + newPhasePresence = bothPhases; + if (formulation == pnsw) + globalSol[dofIdxGlobal][switchIdx] = 0.999; + else if (formulation == pwsn) + globalSol[dofIdxGlobal][switchIdx] = 0.001; + } + } + else if (phasePresence == bothPhases) + { + Scalar Smin = 0.0; + if (staticDat_[dofIdxGlobal].wasSwitched) + Smin = -0.01; + + if (volVars.saturation(nPhaseIdx) <= Smin) + { + wouldSwitch = true; + // nonwetting phase disappears + std::cout << "Nonwetting phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sn: " + << volVars.saturation(nPhaseIdx) << std::endl; + newPhasePresence = wPhaseOnly; + + if(useMoles) // mole-fraction formulation + { + globalSol[dofIdxGlobal][switchIdx] + = volVars.moleFraction(wPhaseIdx, nCompIdx); + } + else // mass-fraction formulation + { + globalSol[dofIdxGlobal][switchIdx] + = volVars.massFraction(wPhaseIdx, nCompIdx); + } + } + else if (volVars.saturation(wPhaseIdx) <= Smin) + { + wouldSwitch = true; + // wetting phase disappears + std::cout << "Wetting phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sw: " + << volVars.saturation(wPhaseIdx) << std::endl; + newPhasePresence = nPhaseOnly; + + if(useMoles) // mole-fraction formulation + { + globalSol[dofIdxGlobal][switchIdx] + = volVars.moleFraction(nPhaseIdx, wCompIdx); + } + else // mass-fraction formulation + { + globalSol[dofIdxGlobal][switchIdx] + = volVars.massFraction(nPhaseIdx, wCompIdx); + } + } + } + + staticDat_[dofIdxGlobal].phasePresence = newPhasePresence; + staticDat_[dofIdxGlobal].wasSwitched = wouldSwitch; + return phasePresence != newPhasePresence; + } + +protected: + // parameters given in constructor + std::vector<StaticVars> staticDat_; + bool switchFlag_; +}; + +} + +#include "propertydefaults.hh" + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/newtoncontroller.hh b/dumux/porousmediumflow/2p2c/implicit/newtoncontroller.hh new file mode 100644 index 0000000000..db9579b3c2 --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/newtoncontroller.hh @@ -0,0 +1,104 @@ +// -*- 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 A two-phase two-component specific controller for the Newton solver. + */ +#ifndef DUMUX_2P2C_NEWTON_CONTROLLER_HH +#define DUMUX_2P2C_NEWTON_CONTROLLER_HH + +#include "properties.hh" + +#include <dumux/nonlinear/newtoncontroller.hh> + +namespace Dumux { + +/*! + * \ingroup Newton + * \ingroup TwoPTwoCModel + * \brief A two-phase two-component specific controller for the Newton solver. + * + * This controller 'knows' what a 'physically meaningful' solution is + * which allows the Newton method to abort earlier if the solution is + * way out of bounds. + */ +template <class TypeTag> +class TwoPTwoCNewtonController : public NewtonController<TypeTag> +{ + typedef NewtonController<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + +public: + TwoPTwoCNewtonController(const Problem &problem) + : ParentType(problem) + {} + + /*! + * \brief Suggest a new time step size based either on the number of Newton + * iterations required or on the variable switch + * + * \param uCurrentIter The current global solution vector + * \param uLastIter The previous global solution vector + * + */ + void newtonEndStep(SolutionVector &uCurrentIter, + const SolutionVector &uLastIter) + { + int succeeded; + try { + // call the method of the base class + this->method().model().updateStaticData(uCurrentIter, uLastIter); + ParentType::newtonEndStep(uCurrentIter, uLastIter); + + succeeded = 1; + if (this->gridView_().comm().size() > 1) + succeeded = this->gridView_().comm().min(succeeded); + } + catch (Dumux::NumericalProblem &e) + { + std::cout << "rank " << this->problem_().gridView().comm().rank() + << " caught an exception while updating:" << e.what() + << "\n"; + succeeded = 0; + if (this->gridView_().comm().size() > 1) + succeeded = this->gridView_().comm().min(succeeded); + } + + if (!succeeded) { + DUNE_THROW(NumericalProblem, + "A process did not succeed in linearizing the system"); + } + } + + /*! + * \brief Returns true if the current solution can be considered to + * be accurate enough + */ + bool newtonConverged() + { + if (this->method().model().switched()) + return false; + + return ParentType::newtonConverged(); + } +}; +} + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/properties.hh b/dumux/porousmediumflow/2p2c/implicit/properties.hh new file mode 100644 index 0000000000..3f8da55d76 --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/properties.hh @@ -0,0 +1,85 @@ +// -*- 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 TwoPTwoCModel + * + * \file + * + * \brief Defines the properties required for the two-phase two-component + * fully implicit model. + */ +#ifndef DUMUX_2P2C_PROPERTIES_HH +#define DUMUX_2P2C_PROPERTIES_HH + +#include <dumux/implicit/box/properties.hh> +#include <dumux/implicit/cellcentered/properties.hh> +#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> + +namespace Dumux +{ + +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tags for the implicit isothermal two-phase two-component problems +NEW_TYPE_TAG(TwoPTwoC); +NEW_TYPE_TAG(BoxTwoPTwoC, INHERITS_FROM(BoxModel, TwoPTwoC)); +NEW_TYPE_TAG(CCTwoPTwoC, INHERITS_FROM(CCModel, TwoPTwoC)); + +//! The type tags for the corresponding non-isothermal problems +NEW_TYPE_TAG(TwoPTwoCNI, INHERITS_FROM(TwoPTwoC, NonIsothermal)); +NEW_TYPE_TAG(BoxTwoPTwoCNI, INHERITS_FROM(BoxModel, TwoPTwoCNI)); +NEW_TYPE_TAG(CCTwoPTwoCNI, INHERITS_FROM(CCModel, TwoPTwoCNI)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system +NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system +NEW_PROP_TAG(Indices); //!< Enumerations for the model +NEW_PROP_TAG(Formulation); //!< The formulation of the model +NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters +NEW_PROP_TAG(FluidSystem); //!< The type of the multi-component relations +NEW_PROP_TAG(FluidState); //!< The type of the 2p2c fluid state + +NEW_PROP_TAG(MaterialLaw); //!< The material law which ought to be used (extracted from the spatial parameters) +NEW_PROP_TAG(MaterialLawParams); //!< The parameters of the material law (extracted from the spatial parameters) +NEW_PROP_TAG(EffectiveDiffusivityModel); //!< The employed model for the computation of the effective diffusivity + +NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem +NEW_PROP_TAG(UseMoles); //!< Defines whether mole (true) or mass (false) fractions are used +NEW_PROP_TAG(UseConstraintSolver); //!< Determines whether the constraint solver should be used + +NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The value of the upwind weight for the mass conservation equations +NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation +NEW_PROP_TAG(ReplaceCompEqIdx); //!< The index of the total mass balance equation, + //!< if one component balance is replaced (ReplaceCompEqIdx < NumComponents) +NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the VTK output +NEW_PROP_TAG(BaseFluxVariables); //!< The base flux variables +NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient +} +} + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/propertydefaults.hh b/dumux/porousmediumflow/2p2c/implicit/propertydefaults.hh new file mode 100644 index 0000000000..04d0b6203a --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/propertydefaults.hh @@ -0,0 +1,232 @@ +// -*- 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 TwoPTwoCModel + * \file + * + * \brief Defines default values for most properties required by the + * two-phase two-component fully implicit model. + */ +#ifndef DUMUX_2P2C_PROPERTY_DEFAULTS_HH +#define DUMUX_2P2C_PROPERTY_DEFAULTS_HH + +#include "properties.hh" +#include "model.hh" +#include "indices.hh" +#include "fluxvariables.hh" +#include "volumevariables.hh" +#include "localresidual.hh" +#include "newtoncontroller.hh" + +#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> +#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> +#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> +#include <dumux/material/spatialparams/implicitspatialparams.hh> +#include <dumux/material/fluidmatrixinteractions/2p/thermalconductivitysomerton.hh> + +namespace Dumux +{ + +namespace Properties { +////////////////////////////////////////////////////////////////// +// Property values +////////////////////////////////////////////////////////////////// + +/*! + * \brief Set the property for the number of components. + * + * We just forward the number from the fluid system and use a static + * assert to make sure it is 2. + */ +SET_PROP(TwoPTwoC, NumComponents) +{ + private: + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + public: + static const int value = FluidSystem::numComponents; + + static_assert(value == 2, + "Only fluid systems with 2 components are supported by the 2p-2c model!"); +}; + +/*! + * \brief Set the property for the number of fluid phases. + * + * We just forward the number from the fluid system and use a static + * assert to make sure it is 2. + */ +SET_PROP(TwoPTwoC, NumPhases) +{ + private: + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + public: + static const int value = FluidSystem::numPhases; + static_assert(value == 2, + "Only fluid systems with 2 phases are supported by the 2p-2c model!"); +}; + +/*! + * \brief The fluid state which is used by the volume variables to + * store the thermodynamic state. This should be chosen + * appropriately for the model ((non-)isothermal, equilibrium, ...). + * This can be done in the problem. + */ +SET_PROP(TwoPTwoC, 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 the number of equations to 2 +SET_INT_PROP(TwoPTwoC, NumEq, 2); + +//! Set the default formulation to pw-sn +SET_INT_PROP(TwoPTwoC, + Formulation, + TwoPTwoCFormulation::pwsn); + +//! Set as default that no component mass balance is replaced by the total mass balance +SET_INT_PROP(TwoPTwoC, ReplaceCompEqIdx, 2); + +//! Set the property for the material parameters by extracting it from the material law. +SET_PROP(TwoPTwoC, MaterialLawParams) +{ + private: + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + + public: + typedef typename MaterialLaw::Params type; +}; + +//! Use the 2p2c local residual operator +SET_TYPE_PROP(TwoPTwoC, + LocalResidual, + TwoPTwoCLocalResidual<TypeTag>); + +//! Use the 2p2c Newton controller +SET_TYPE_PROP(TwoPTwoC, NewtonController, TwoPTwoCNewtonController<TypeTag>); + +//! Use the 2p2c model +SET_TYPE_PROP(TwoPTwoC, Model, TwoPTwoCModel<TypeTag>); + +//! Use the 2p2c VolumeVariables +SET_TYPE_PROP(TwoPTwoC, VolumeVariables, TwoPTwoCVolumeVariables<TypeTag>); + +//! Use the 2p2c FluxVariables +SET_TYPE_PROP(TwoPTwoC, FluxVariables, TwoPTwoCFluxVariables<TypeTag>); + +//! Set the BaseFluxVariables to realize Darcy flow +SET_TYPE_PROP(TwoPTwoC, BaseFluxVariables, ImplicitDarcyFluxVariables<TypeTag>); + +//! Set the upwind weight for the mass conservation equations +SET_SCALAR_PROP(TwoPTwoC, ImplicitMassUpwindWeight, 1.0); + +//! Set default mobility upwind weight to 1.0, i.e. fully upwind +SET_SCALAR_PROP(TwoPTwoC, ImplicitMobilityUpwindWeight, 1.0); + +//! Set the indices required by the isothermal 2p2c +SET_PROP(TwoPTwoC, Indices) +{ private: + enum { Formulation = GET_PROP_VALUE(TypeTag, Formulation) }; + public: + typedef TwoPTwoCIndices<TypeTag, Formulation, 0> type; +}; + +//! Use the ImplicitSpatialParams by default +SET_TYPE_PROP(TwoPTwoC, SpatialParams, ImplicitSpatialParams<TypeTag>); + +//! Use the model after Millington (1961) for the effective diffusivity +SET_PROP(TwoPTwoC, EffectiveDiffusivityModel) +{ private : + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + public: + typedef DiffusivityMillingtonQuirk<Scalar> type; +}; + +//! Disable velocity output by default +SET_BOOL_PROP(TwoPTwoC, VtkAddVelocity, false); + +//! Enable gravity by default +SET_BOOL_PROP(TwoPTwoC, ProblemEnableGravity, true); + +//! Use mole fractions in the balance equations by default +SET_BOOL_PROP(TwoPTwoC, UseMoles, true); + +//! Determines whether the constraint solver is used +SET_BOOL_PROP(TwoPTwoC, UseConstraintSolver, true); + +//! Set default value for the Forchheimer coefficient +// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. +// Actually the Forchheimer coefficient is also a function of the dimensions of the +// porous medium. Taking it as a constant is only a first approximation +// (Nield, Bejan, Convection in porous media, 2006, p. 10) +SET_SCALAR_PROP(TwoPTwoC, SpatialParamsForchCoeff, 0.55); + +//! Somerton is used as default model to compute the effective thermal heat conductivity +SET_PROP(TwoPTwoCNI, ThermalConductivityModel) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; +public: + typedef ThermalConductivitySomerton<Scalar, Indices> type; +}; + +//! temperature is already written by the isothermal model +SET_BOOL_PROP(TwoPTwoCNI, NiOutputLevel, 0); + +////////////////////////////////////////////////////////////////// +// Property values for isothermal model required for the general non-isothermal model +////////////////////////////////////////////////////////////////// + +// set isothermal Model +SET_TYPE_PROP(TwoPTwoCNI, IsothermalModel, TwoPTwoCModel<TypeTag>); + +// set isothermal FluxVariables +SET_TYPE_PROP(TwoPTwoCNI, IsothermalFluxVariables, TwoPTwoCFluxVariables<TypeTag>); + +//set isothermal VolumeVariables +SET_TYPE_PROP(TwoPTwoCNI, IsothermalVolumeVariables, TwoPTwoCVolumeVariables<TypeTag>); + +//set isothermal LocalResidual +SET_TYPE_PROP(TwoPTwoCNI, IsothermalLocalResidual, TwoPTwoCLocalResidual<TypeTag>); + +//set isothermal Indices +SET_PROP(TwoPTwoCNI, IsothermalIndices) +{ +private: + enum { Formulation = GET_PROP_VALUE(TypeTag, Formulation) }; +public: + typedef TwoPTwoCIndices<TypeTag, Formulation, 0> type; +}; + +//set isothermal NumEq +SET_INT_PROP(TwoPTwoCNI, IsothermalNumEq, 2); + +} + +} + +#endif diff --git a/dumux/porousmediumflow/2p2c/implicit/volumevariables.hh b/dumux/porousmediumflow/2p2c/implicit/volumevariables.hh new file mode 100644 index 0000000000..88b20bb907 --- /dev/null +++ b/dumux/porousmediumflow/2p2c/implicit/volumevariables.hh @@ -0,0 +1,621 @@ +// -*- 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 Contains the quantities which are constant within a + * finite volume in the two-phase two-component model. + */ +#ifndef DUMUX_2P2C_VOLUME_VARIABLES_HH +#define DUMUX_2P2C_VOLUME_VARIABLES_HH + +#include <dumux/implicit/model.hh> +#include <dumux/material/fluidstates/compositionalfluidstate.hh> +#include <dumux/material/constraintsolvers/computefromreferencephase.hh> +#include <dumux/material/constraintsolvers/misciblemultiphasecomposition.hh> +#include "properties.hh" +#include "indices.hh" + +namespace Dumux +{ + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are constant within a + * finite volume in the two-phase two-component model. + */ +template <class TypeTag> +class TwoPTwoCVolumeVariables : public ImplicitVolumeVariables<TypeTag> +{ + typedef ImplicitVolumeVariables<TypeTag> ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; + enum { + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents) + }; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx, + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx + }; + + // present phases + enum { + wPhaseOnly = Indices::wPhaseOnly, + nPhaseOnly = Indices::nPhaseOnly, + bothPhases = Indices::bothPhases + }; + + // formulations + enum { + formulation = GET_PROP_VALUE(TypeTag, Formulation), + pwsn = TwoPTwoCFormulation::pwsn, + pnsw = TwoPTwoCFormulation::pnsw + }; + + // primary variable indices + enum { + switchIdx = Indices::switchIdx, + pressureIdx = Indices::pressureIdx + }; + + 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 typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef Dumux::MiscibleMultiPhaseComposition<Scalar, FluidSystem> MiscibleMultiPhaseComposition; + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + static const bool useConstraintSolver = GET_PROP_VALUE(TypeTag, UseConstraintSolver); + static_assert(useMoles || (!useMoles && useConstraintSolver), + "if UseMoles is set false, UseConstraintSolver has to be set to true"); + typedef Dumux::ComputeFromReferencePhase<Scalar, FluidSystem> ComputeFromReferencePhase; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + +public: + + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; + + /*! + * \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); + + completeFluidState(priVars, problem, element, fvGeometry, scvIdx, fluidState_, isOldSol); + + ///////////// + // calculate the remaining quantities + ///////////// + const MaterialLawParams &materialParams = + problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); + + // Second instance of a parameter cache. + // Could be avoided if diffusion coefficients also + // became part of the fluid state. + typename FluidSystem::ParameterCache paramCache; + paramCache.updateAll(fluidState_); + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + + + // relative permeabilities + Scalar kr; + if (phaseIdx == wPhaseIdx) + kr = MaterialLaw::krw(materialParams, saturation(wPhaseIdx)); + else // ATTENTION: krn requires the wetting phase saturation + // as parameter! + kr = MaterialLaw::krn(materialParams, saturation(wPhaseIdx)); + relativePermeability_[phaseIdx] = kr; + Valgrind::CheckDefined(relativePermeability_[phaseIdx]); + + // binary diffusion coefficients + diffCoeff_[phaseIdx] = + FluidSystem::binaryDiffusionCoefficient(fluidState_, + paramCache, + phaseIdx, + wCompIdx, + nCompIdx); + Valgrind::CheckDefined(diffCoeff_[phaseIdx]); + } + + // porosity + porosity_ = problem.spatialParams().porosity(element, + fvGeometry, + scvIdx); + Valgrind::CheckDefined(porosity_); + + // energy related quantities not contained in the fluid state + asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol); + } + + /*! + * \copydoc ImplicitModel::completeFluidState + * \param isOldSol Specifies whether this is the previous solution or the current one + */ + static void completeFluidState(const PrimaryVariables& priVars, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + int scvIdx, + FluidState& fluidState, + bool isOldSol = false) + { + Scalar t = Implementation::temperature_(priVars, problem, element, + fvGeometry, scvIdx); + fluidState.setTemperature(t); + int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); + int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); + + ///////////// + // set the saturations + ///////////// + Scalar sn; + if (phasePresence == nPhaseOnly) + sn = 1.0; + else if (phasePresence == wPhaseOnly) { + sn = 0.0; + } + else if (phasePresence == bothPhases) { + if (formulation == pwsn) + sn = priVars[switchIdx]; + else if (formulation == pnsw) + sn = 1.0 - priVars[switchIdx]; + else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); + } + else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); + fluidState.setSaturation(wPhaseIdx, 1 - sn); + fluidState.setSaturation(nPhaseIdx, sn); + + ///////////// + // set the pressures of the fluid phases + ///////////// + + // calculate capillary pressure + const MaterialLawParams &materialParams = + problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); + Scalar pc = MaterialLaw::pc(materialParams, 1 - sn); + + if (formulation == pwsn) { + fluidState.setPressure(wPhaseIdx, priVars[pressureIdx]); + fluidState.setPressure(nPhaseIdx, priVars[pressureIdx] + pc); + } + else if (formulation == pnsw) { + fluidState.setPressure(nPhaseIdx, priVars[pressureIdx]); + fluidState.setPressure(wPhaseIdx, priVars[pressureIdx] - pc); + } + else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); + + ///////////// + // calculate the phase compositions + ///////////// + typename FluidSystem::ParameterCache paramCache; + + //get the phase pressures and set the fugacity coefficients here if constraintsolver is not used + Scalar pn = 0; + Scalar pw = 0; + + if(!useConstraintSolver) { + if (formulation == pwsn) { + pw = priVars[pressureIdx]; + pn = pw + pc; + } + else { + pn = priVars[pressureIdx]; + pw = pn - pc; + } + + for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { + assert(FluidSystem::isIdealMixture(phaseIdx)); + + for (int compIdx = 0; compIdx < numComponents; ++ compIdx) { + Scalar phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx); + fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi); + } + } + } + + // now comes the tricky part: calculate phase compositions + if (phasePresence == bothPhases) { + // both phases are present, phase compositions are a + // result of the the nonwetting <-> wetting equilibrium. This is + // the job of the "MiscibleMultiPhaseComposition" + // constraint solver + if(useConstraintSolver) { + MiscibleMultiPhaseComposition::solve(fluidState, + paramCache, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + // ... or calculated explicitly this way ... + else { + //get the partial pressure of the main component of the the wetting phase ("H20") within the nonwetting (gas) phase == vapor pressure due to equilibrium + //note that in this case the fugacityCoefficient * pw is the vapor pressure (see implementation in respective fluidsystem) + Scalar partPressH2O = FluidSystem::fugacityCoefficient(fluidState, + wPhaseIdx, + wCompIdx) * pw; + + // get the partial pressure of the main component of the the nonwetting (gas) phase ("Air") + Scalar partPressAir = pn - partPressH2O; + + //calculate the mole fractions of the components within the nonwetting phase + Scalar xnn = partPressAir/pn; + Scalar xnw = partPressH2O/pn; + + // calculate the mole fractions of the components within the wetting phase + //note that in this case the fugacityCoefficient * pw is the Henry Coefficient (see implementation in respective fluidsystem) + Scalar xwn = partPressAir + / (FluidSystem::fugacityCoefficient(fluidState, + wPhaseIdx,nCompIdx) + * pw); + + Scalar xww = 1.0 -xwn; + + //set all mole fractions + fluidState.setMoleFraction(wPhaseIdx, wCompIdx, xww); + fluidState.setMoleFraction(wPhaseIdx, nCompIdx, xwn); + fluidState.setMoleFraction(nPhaseIdx, wCompIdx, xnw); + fluidState.setMoleFraction(nPhaseIdx, nCompIdx, xnn); + + paramCache.updateComposition(fluidState, wPhaseIdx); + paramCache.updateComposition(fluidState, nPhaseIdx); + + //set the phase densities + Scalar rhoW = FluidSystem::density(fluidState, paramCache, wPhaseIdx); + Scalar rhoN = FluidSystem::density(fluidState, paramCache, nPhaseIdx); + + fluidState.setDensity(wPhaseIdx, rhoW); + fluidState.setDensity(nPhaseIdx, rhoN); + } + } + else if (phasePresence == nPhaseOnly) { + // only the nonwetting phase is present, i.e. nonwetting phase + // composition is stored explicitly. + if(useMoles) + { + fluidState.setMoleFraction(nPhaseIdx, nCompIdx, 1 - priVars[switchIdx]); + fluidState.setMoleFraction(nPhaseIdx, wCompIdx, priVars[switchIdx]); + } + else + { + // setMassFraction() has only to be called 1-numComponents times + fluidState.setMassFraction(nPhaseIdx, wCompIdx, priVars[switchIdx]); + } + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). This is the job + // of the "ComputeFromReferencePhase" constraint solver + if (useConstraintSolver) { + ComputeFromReferencePhase::solve(fluidState, + paramCache, + nPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + // ... or calculated explicitly this way ... + else { + // note that the water phase is actually not existing! + // thus, this is used as phase switch criterion + Scalar xnw = priVars[switchIdx]; + Scalar xnn = 1.0 -xnw; + + //first, xww: + // xnw * pn = "actual" (hypothetical) vapor pressure + // fugacityCoefficient * pw = vapor pressure given by thermodynamic conditions + // Here, xww is not actually the mole fraction of water in the wetting phase + // xww is only the ratio of "actual" vapor pressure / "thermodynamic" vapor pressure + // If xww > 1 : gas is over-saturated with water vapor, + // condensation takes place (see switch criterion in model) + Scalar xww = xnw * pn + / (FluidSystem::fugacityCoefficient(fluidState, + wPhaseIdx,wCompIdx) + * pw); + + // now, xwn: + //partialPressure / xwn = Henry + //partialPressure = xnn * pn + //xwn = xnn * pn / Henry + // Henry = fugacityCoefficient * pw + Scalar xwn = xnn * pn / (FluidSystem::fugacityCoefficient(fluidState, + wPhaseIdx,nCompIdx) + * pw); + + fluidState.setMoleFraction(wPhaseIdx, wCompIdx, xww); + fluidState.setMoleFraction(wPhaseIdx, nCompIdx, xwn); + + paramCache.updateComposition(fluidState, wPhaseIdx); + paramCache.updateComposition(fluidState, nPhaseIdx); + + Scalar rhoW = FluidSystem::density(fluidState, paramCache, wPhaseIdx); + Scalar rhoN = FluidSystem::density(fluidState, paramCache, nPhaseIdx); + + fluidState.setDensity(wPhaseIdx, rhoW); + fluidState.setDensity(nPhaseIdx, rhoN); + } + } + else if (phasePresence == wPhaseOnly) { + // only the wetting phase is present, i.e. wetting phase + // composition is stored explicitly. + if(useMoles) // mole-fraction formulation + { + fluidState.setMoleFraction(wPhaseIdx, wCompIdx, 1-priVars[switchIdx]); + fluidState.setMoleFraction(wPhaseIdx, nCompIdx, priVars[switchIdx]); + } + else // mass-fraction formulation + { + // setMassFraction() has only to be called 1-numComponents times + fluidState.setMassFraction(wPhaseIdx, nCompIdx, priVars[switchIdx]); + } + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). This is the job + // of the "ComputeFromReferencePhase" constraint solver + if (useConstraintSolver) { + ComputeFromReferencePhase::solve(fluidState, + paramCache, + wPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + // ... or calculated explicitly this way ... + else { + // note that the gas phase is actually not existing! + // thus, this is used as phase switch criterion + Scalar xwn = priVars[switchIdx]; + + //first, xnw: + //psteam = xnw * pn = partial pressure of water in gas phase + //psteam = fugacityCoefficient * pw + Scalar xnw = (FluidSystem::fugacityCoefficient(fluidState, + wPhaseIdx,wCompIdx) + * pw) / pn ; + + //now, xnn: + // xwn = partialPressure / Henry + // partialPressure = pn * xnn + // xwn = pn * xnn / Henry + // xnn = xwn * Henry / pn + // Henry = fugacityCoefficient * pw + Scalar xnn = xwn * (FluidSystem::fugacityCoefficient(fluidState, + wPhaseIdx,nCompIdx) + * pw) / pn ; + + fluidState.setMoleFraction(nPhaseIdx, nCompIdx, xnn); + fluidState.setMoleFraction(nPhaseIdx, wCompIdx, xnw); + + paramCache.updateComposition(fluidState, wPhaseIdx); + paramCache.updateComposition(fluidState, nPhaseIdx); + + Scalar rhoW = FluidSystem::density(fluidState, paramCache, wPhaseIdx); + Scalar rhoN = FluidSystem::density(fluidState, paramCache, nPhaseIdx); + + fluidState.setDensity(wPhaseIdx, rhoW); + fluidState.setDensity(nPhaseIdx, rhoN); + } + } + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + //set the viscosity here if constraintsolver is not used + if(!useConstraintSolver) { + const Scalar mu = + FluidSystem::viscosity(fluidState, + paramCache, + phaseIdx); + fluidState.setViscosity(phaseIdx,mu); + } + // compute and set the enthalpy + Scalar h = Implementation::enthalpy_(fluidState, paramCache, phaseIdx); + fluidState.setEnthalpy(phaseIdx, h); + } + } + + + /*! + * \brief Returns the phase state within the control volume. + */ + const FluidState &fluidState() const + { return fluidState_; } + + /*! + * \brief Returns the saturation of a given phase within + * the control volume in \f$[-]\f$. + * + * \param phaseIdx The phase index + */ + Scalar saturation(const int phaseIdx) const + { return fluidState_.saturation(phaseIdx); } + + /*! + * \brief Returns the mass fraction of a given component in a + * given phase within the control volume in \f$[-]\f$. + * + * \param phaseIdx The phase index + * \param compIdx The component index + */ + Scalar massFraction(const int phaseIdx, const int compIdx) const + { return fluidState_.massFraction(phaseIdx, compIdx); } + + /*! + * \brief Returns the mole fraction of a given component in a + * given phase within the control volume in \f$[-]\f$. + * + * \param phaseIdx The phase index + * \param compIdx The component index + */ + Scalar moleFraction(const int phaseIdx, const int compIdx) const + { return fluidState_.moleFraction(phaseIdx, compIdx); } + + /*! + * \brief Returns the mass density of a given phase within the + * control volume in \f$[kg/m^3]\f$. + * + * \param phaseIdx The phase index + */ + Scalar density(const int phaseIdx) const + { return fluidState_.density(phaseIdx); } + + /*! + * \brief Returns the dynamic viscosity of the fluid within the + * control volume in \f$\mathrm{[Pa s]}\f$. + * + * \param phaseIdx The phase index + */ + Scalar viscosity(const int phaseIdx) const + { return fluidState_.viscosity(phaseIdx); } + + /*! + * \brief Returns the mass density of a given phase within the + * control volume in \f$[mol/m^3]\f$. + * + * \param phaseIdx The phase index + */ + Scalar molarDensity(const int phaseIdx) const + { return fluidState_.density(phaseIdx) / fluidState_.averageMolarMass(phaseIdx); } + + /*! + * \brief Returns the effective pressure of a given phase within + * the control volume in \f$[kg/(m*s^2)=N/m^2=Pa]\f$. + * + * \param phaseIdx The phase index + */ + Scalar pressure(const int phaseIdx) const + { return fluidState_.pressure(phaseIdx); } + + /*! + * \brief Returns temperature within the control volume in \f$[K]\f$. + * + * Note that we assume thermodynamic equilibrium, i.e. the + * temperature of the rock matrix and of all fluid phases are + * identical. + */ + Scalar temperature() const + { return fluidState_.temperature(/*phaseIdx=*/0); } + + /*! + * \brief Returns the relative permeability of a given phase within + * the control volume in \f$[-]\f$. + * + * \param phaseIdx The phase index + */ + Scalar relativePermeability(const int phaseIdx) const + { + return relativePermeability_[phaseIdx]; + } + + /*! + * \brief Returns the effective mobility of a given phase within + * the control volume in \f$[s*m/kg]\f$. + * + * \param phaseIdx The phase index + */ + Scalar mobility(const int phaseIdx) const + { + return relativePermeability_[phaseIdx]/fluidState_.viscosity(phaseIdx); + } + + /*! + * \brief Returns the effective capillary pressure within the control volume + * in \f$[kg/(m*s^2)=N/m^2=Pa]\f$. + */ + Scalar capillaryPressure() const + { return fluidState_.pressure(nPhaseIdx) - fluidState_.pressure(wPhaseIdx); } + + /*! + * \brief Returns the average porosity within the control volume in \f$[-]\f$. + */ + Scalar porosity() const + { return porosity_; } + + /*! + * \brief Returns the binary diffusion coefficients for a phase in \f$[m^2/s]\f$. + */ + Scalar diffCoeff(const int phaseIdx) const + { return diffCoeff_[phaseIdx]; } + + +protected: + static Scalar temperature_(const PrimaryVariables &priVars, + const Problem& problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx) + { + return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); + } + + template<class ParameterCache> + static Scalar enthalpy_(const FluidState& fluidState, + const ParameterCache& paramCache, + const int phaseIdx) + { + return 0; + } + + /*! + * \brief Called by update() to compute the energy related quantities + */ + void updateEnergy_(const PrimaryVariables &sol, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx, + bool isOldSol) + { } + + Scalar porosity_; //!< Effective porosity within the control volume + Scalar relativePermeability_[numPhases]; //!< Relative permeability within the control volume + Scalar diffCoeff_[numPhases]; //!< Binary diffusion coefficients for the phases + FluidState fluidState_; + +private: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } + + +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/fluxvariables.hh b/dumux/porousmediumflow/2pnc/implicit/fluxvariables.hh new file mode 100644 index 0000000000..8f85e0d0ae --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/fluxvariables.hh @@ -0,0 +1,415 @@ +// -*- 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 Contains the data which is required to calculate + * all fluxes of components over a face of a finite volume for + * the two-phase two-component model fully implicit model. + */ +#ifndef DUMUX_2PNC_FLUX_VARIABLES_HH +#define DUMUX_2PNC_FLUX_VARIABLES_HH + +#include <dumux/common/math.hh> +#include <dumux/common/spline.hh> + +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup TwoPNCModel + * \ingroup ImplicitFluxVariables + * \brief Contains the data which is required to calculate + * all fluxes of components over a face of a finite volume for + * the two-phase n-component fully implicit model. + * + * This means pressure and concentration gradients, phase densities at + * the integration point, etc. + */ + +template <class TypeTag> +class TwoPNCFluxVariables : public GET_PROP_TYPE(TypeTag, BaseFluxVariables) +{ + typedef typename GET_PROP_TYPE(TypeTag, BaseFluxVariables) BaseFluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + + typedef typename GridView::ctype CoordScalar; + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + + enum { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + }; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; +// typedef typename FVElementGeometry::SubControlVolume SCV; + typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; + + typedef Dune::FieldVector<CoordScalar, dimWorld> DimVector; + typedef Dune::FieldMatrix<CoordScalar, dim, dim> DimMatrix; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + wPhaseIdx = FluidSystem::wPhaseIdx, + nPhaseIdx = FluidSystem::nPhaseIdx, + wCompIdx = FluidSystem::wCompIdx, + }; + +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 sub-control-volume face + * \param elemVolVars The volume variables of the current element + * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face + */ + TwoPNCFluxVariables(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : BaseFluxVariables(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) + { + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + density_[phaseIdx] = Scalar(0); + molarDensity_[phaseIdx] = Scalar(0); + potentialGrad_[phaseIdx] = Scalar(0); + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + massFractionGrad_[phaseIdx][compIdx] = Scalar(0); + moleFractionGrad_[phaseIdx][compIdx] = Scalar(0); + } + } + calculateGradients_(problem, element, elemVolVars); + calculateVelocities_(problem, element, elemVolVars); + calculateporousDiffCoeff_(problem, element, elemVolVars); + }; + +protected: + void calculateGradients_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + // calculate gradients + DimVector tmp(0.0); + for (int idx = 0; + idx < this->fvGeometry_.numScv; + idx++) // loop over adjacent vertices + { + // FE gradient at vertex idx + const DimVector &feGrad = face().grad[idx]; + + // compute sum of pressure gradients for each phase + for (int phaseIdx = 0; phaseIdx < numPhases; phaseIdx++) + { + // the pressure gradient + tmp = feGrad; + tmp *= elemVolVars[idx].pressure(phaseIdx); //FE grad times phase pressure + potentialGrad_[phaseIdx] += tmp; + } + + // the concentration gradient of the non-wetting + // component in the wetting phase + + for(int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for(int compIdx = 0; compIdx < numComponents; ++compIdx) + { + if(compIdx != phaseIdx) //No grad is needed for this case + { + tmp = feGrad; + tmp *= elemVolVars[idx].massFraction(phaseIdx, compIdx); + massFractionGrad_[phaseIdx][compIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[idx].moleFraction(phaseIdx, compIdx); + moleFractionGrad_[phaseIdx][compIdx] += tmp; + } + } + } + } + + // correct the pressure gradients by the hydrostatic + // pressure due to gravity + for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) + { + int i = face().i; + int j = face().j; + Scalar fI = rhoFactor_(phaseIdx, i, elemVolVars); + Scalar fJ = rhoFactor_(phaseIdx, j, elemVolVars); + if (fI + fJ <= 0) + fI = fJ = 0.5; // doesn't matter because no phase is + // present in both cells! + density_[phaseIdx] = + (fI*elemVolVars[i].density(phaseIdx) + + fJ*elemVolVars[j].density(phaseIdx)) + / + (fI + fJ); + // phase density + molarDensity_[phaseIdx] + = + (fI*elemVolVars[i].molarDensity(phaseIdx) + + fJ*elemVolVars[j].molarDensity(phaseIdx)) + / + (fI + fJ); //arithmetic averaging + + tmp = problem.gravity(); + tmp *= density_[phaseIdx]; + + potentialGrad_[phaseIdx] -= tmp; + } + } + + Scalar rhoFactor_(int phaseIdx, int scvIdx, const ElementVolumeVariables &vDat) + { + + static const Scalar eps = 1e-2; + const Scalar sat = vDat[scvIdx].density(phaseIdx); + if (sat > eps) + return 0.5; + if (sat <= 0) + return 0; + + static const Dumux::Spline<Scalar> sp(0, eps, // x0, x1 + 0, 0.5, // y0, y1 + 0, 0); // m0, m1 + return sp.eval(sat); + } + + void calculateVelocities_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + const SpatialParams &spatialParams = problem.spatialParams(); + // multiply the pressure potential with the intrinsic + // permeability + DimMatrix K(0.0); + + for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) + { + auto K_i = spatialParams.intrinsicPermeability(element,this->fvGeometry_,face().i); + //K_i *= volVarsI.permFactor(); + + auto K_j = spatialParams.intrinsicPermeability(element,this->fvGeometry_,face().j); + //K_j *= volVarsJ.permFactor(); + + spatialParams.meanK(K,K_i,K_j); + + K.mv(potentialGrad_[phaseIdx], Kmvp_[phaseIdx]); + KmvpNormal_[phaseIdx] = - (Kmvp_[phaseIdx] * face().normal); + } + + // set the upstream and downstream vertices + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + upstreamIdx_[phaseIdx] = face().i; + downstreamIdx_[phaseIdx] = face().j; + + if (KmvpNormal_[phaseIdx] < 0) { + std::swap(upstreamIdx_[phaseIdx], + downstreamIdx_[phaseIdx]); + } + } + } + + void calculateporousDiffCoeff_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + const VolumeVariables &volVarsI = elemVolVars[face().i]; + const VolumeVariables &volVarsJ = elemVolVars[face().j]; + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + /* If there is no phase saturation on either side of the face + * no diffusion takes place */ + + if (volVarsI.saturation(phaseIdx) <= 0 || + volVarsJ.saturation(phaseIdx) <= 0) + { + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + porousDiffCoeff_[phaseIdx][compIdx] = 0.0; + } + } + + else + { + // calculate tortuosity at the nodes i and j needed + // for porous media diffusion coefficient + Scalar tauI = 1.0/(volVarsI.porosity() * volVarsI.porosity()) * + pow(volVarsI.porosity() * volVarsI.saturation(phaseIdx), 7.0/3); + + Scalar tauJ = 1.0/(volVarsJ.porosity() * volVarsJ.porosity()) * + pow(volVarsJ.porosity() * volVarsJ.saturation(phaseIdx), 7.0/3); + // Diffusion coefficient in the porous medium + + // -> harmonic mean + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + if(phaseIdx==compIdx) + porousDiffCoeff_[phaseIdx][compIdx] = 0.0; + else + { + porousDiffCoeff_[phaseIdx][compIdx] = harmonicMean(volVarsI.porosity() * volVarsI.saturation(phaseIdx) * tauI * volVarsI.diffCoeff(phaseIdx, compIdx), + volVarsJ.porosity() * volVarsJ.saturation(phaseIdx) * tauJ * volVarsJ.diffCoeff(phaseIdx, compIdx)); + } + } + } + } + } + +public: + /*! + * \brief Return the pressure potential multiplied with the + * intrinsic permeability which goes from vertex i to + * vertex j. + * + * Note that the length of the face's normal is the area of the + * face, so this is not the actual velocity by the integral of + * the velocity over the face's area. Also note that the phase + * mobility is not yet included here since this would require a + * decision on the upwinding approach (which is done in the + * model and/or local residual file). + * + * \param phaseIdx The phase index + */ + Scalar KmvpNormal(int phaseIdx) const + { return KmvpNormal_[phaseIdx]; } + + /*! + * \brief Return the pressure potential multiplied with the + * intrinsic permeability as vector (for velocity output) + * + * \param phaseIdx The phase index + */ + DimVector Kmvp(int phaseIdx) const + { return Kmvp_[phaseIdx]; } + + /*! + * \brief Return the local index of the upstream control volume + * for a given phase. + * + * \param phaseIdx The phase index + */ + int upstreamIdx(int phaseIdx) const + { return upstreamIdx_[phaseIdx]; } + + /*! + * \brief Return the local index of the downstream control volume + * for a given phase. + * + * \param phaseIdx The phase index + */ + int downstreamIdx(int phaseIdx) const + { return downstreamIdx_[phaseIdx]; } + + /*! + * \brief The binary diffusion coefficient for each fluid phase. + * + * \param phaseIdx The phase index + * \param compIdx The component index + */ + Scalar porousDiffCoeff(int phaseIdx, int compIdx) const + { return porousDiffCoeff_[phaseIdx][compIdx];} + + /*! + * \brief Return density \f$\mathrm{[kg/m^3]}\f$ of a phase at the integration + * point. + * + * \param phaseIdx The phase index + */ + Scalar density(int phaseIdx) const + { return density_[phaseIdx]; } + + /*! + * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ of a phase at the integration + * point. + * + * \param phaseIdx The phase index + */ + Scalar molarDensity(int phaseIdx) const + { return molarDensity_[phaseIdx]; } + + /*! + * \brief The concentration gradient of a component in a phase. + * + * \param phaseIdx The phase index + * \param compIdx The component index + */ + const DimVector &massFractionGrad(int phaseIdx, int compIdx) const + { return massFractionGrad_[phaseIdx][compIdx]; } + + /*! + * \brief The molar concentration gradient of a component in a phase. + * + * \param phaseIdx The phase index + * \param compIdx The component index + */ + const DimVector &moleFractionGrad(int phaseIdx, int compIdx) const + { return moleFractionGrad_[phaseIdx][compIdx]; } + + const SCVFace &face() const + { + if (this->onBoundary_) + return this->fvGeometry_.boundaryFace[this->faceIdx_]; + else + return this->fvGeometry_.subContVolFace[this->faceIdx_]; + } + +protected: + + // gradients + DimVector potentialGrad_[numPhases]; + DimVector massFractionGrad_[numPhases][numComponents]; + DimVector moleFractionGrad_[numPhases][numComponents]; + + // density of each face at the integration point + Scalar density_[numPhases], molarDensity_[numPhases]; + + // intrinsic permeability times pressure potential gradient + DimVector Kmvp_[numPhases]; + // projected on the face normal + Scalar KmvpNormal_[numPhases]; + + // local index of the upwind vertex for each phase + int upstreamIdx_[numPhases]; + // local index of the downwind vertex for each phase + int downstreamIdx_[numPhases]; + + // the diffusion coefficient for the porous medium + Dune::FieldMatrix<Scalar, numPhases, numComponents> porousDiffCoeff_; +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/indices.hh b/dumux/porousmediumflow/2pnc/implicit/indices.hh new file mode 100644 index 0000000000..a527345942 --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/indices.hh @@ -0,0 +1,80 @@ +// -*- 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 indices required for the two-phase n-component + * fully implicit model. + */ +#ifndef DUMUX_2PNC_INDICES_HH +#define DUMUX_2PNC_INDICES_HH +#include "properties.hh" +namespace Dumux +{ +/*! + * \ingroup TwoPNCModel + * \ingroup ImplicitIndices + * \brief Enumerates the formulations which the two-phase n-component model accepts. + * + */ +struct TwoPNCFormulation//TODO: This might need to be change similar to 2p2c indices +{ + enum { + plSg, + pgSl, + pnSw = pgSl, + pwSn = plSg + }; +}; + +/*! + * \ingroup TwoPNCModel + * \ingroup ImplicitIndices + * \brief The indices for the isothermal two-phase n-component model. + * + * \tparam PVOffset The first index in a primary variable vector. + */ +template <class TypeTag, int PVOffset = 0> +class TwoPNCIndices +{ + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + +public: + // Phase indices + static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< Index of the wetting phase + static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< Index of the non-wetting phase + // present phases (-> 'pseudo' primary variable) + static const int wPhaseOnly = 1; //!< Only the non-wetting phase is present + static const int nPhaseOnly = 2; //!< Only the wetting phase is present + static const int bothPhases = 3; //!< Both phases are present + + // Primary variable indices + static const int pressureIdx = PVOffset + 0; //!< Index for wetting/non-wetting phase pressure (depending on formulation) in a solution vector + static const int switchIdx = PVOffset + 1; //!< Index of the either the saturation or the mass fraction of the non-wetting/wetting phase + // equation indices + static const int conti0EqIdx = PVOffset + 0; //!< Reference index for mass conservation equations. + static const int contiWEqIdx = conti0EqIdx + FluidSystem::wCompIdx; //!< Index of the mass conservation equation for the wetting phase major component + static const int contiNEqIdx = conti0EqIdx + FluidSystem::nCompIdx; //!< Index of the mass conservation equation for the non-wetting phase major component +}; + +// \} + +} + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/localresidual.hh b/dumux/porousmediumflow/2pnc/implicit/localresidual.hh new file mode 100644 index 0000000000..bddf0fe962 --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/localresidual.hh @@ -0,0 +1,349 @@ +// -*- 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 Jacobian matrix for problems + * using the two-phase n-component box model. + */ + +#ifndef DUMUX_2PNC_LOCAL_RESIDUAL_BASE_HH +#define DUMUX_2PNC_LOCAL_RESIDUAL_BASE_HH + +#include "properties.hh" +#include "volumevariables.hh" +#include <dumux/nonlinear/newtoncontroller.hh> + +#include <iostream> +#include <vector> + +namespace Dumux +{ +/*! + * \ingroup TwoPNCModel + * \ingroup ImplicitLocalResidual + * \brief Element-wise calculation of the Jacobian matrix for problems + * using the two-phase n-component fully implicit box model. + * + * This class is used to fill the gaps in ImplicitLocalResidual for the two-phase n-component flow. + */ +template<class TypeTag> +class TwoPNCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) +{ +protected: + typedef TwoPNCLocalResidual<TypeTag> ThisType; + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + typedef BoxLocalResidual<TypeTag> ParentType; + + 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, FluidSystem) FluidSystem; + + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + + typedef CompositionalFluidState<Scalar, FluidSystem> FluidState; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum + { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld, + + numEq = GET_PROP_VALUE(TypeTag, NumEq), + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + + replaceCompEqIdx = GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx), + + pressureIdx = Indices::pressureIdx, + switchIdx = Indices::switchIdx, + + wPhaseIdx = FluidSystem::wPhaseIdx, + nPhaseIdx = FluidSystem::nPhaseIdx, + + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx, + + conti0EqIdx = Indices::conti0EqIdx, + + wPhaseOnly = Indices::wPhaseOnly, + nPhaseOnly = Indices::nPhaseOnly, + bothPhases = Indices::bothPhases, + + plSg = TwoPNCFormulation::plSg, + pgSl = TwoPNCFormulation::pgSl, + formulation = GET_PROP_VALUE(TypeTag, Formulation) + }; + + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::ctype CoordScalar; + + +public: + /*! + * \brief Constructor. Sets the upwind weight. + */ + TwoPNCLocalResidual() + { + // 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 storage term of the current solution in a + * single phase. + * + * \param element The element + * \param phaseIdx The index of the fluid phase + */ + void evalPhaseStorage(const Element &element, int phaseIdx) + { + FVElementGeometry fvGeometry; + fvGeometry.update(this->gridView_(), element); + ElementBoundaryTypes bcTypes; + bcTypes.update(this->problem_(), element, fvGeometry); + ElementVolumeVariables volVars; + volVars.update(this->problem_(), element, fvGeometry, false); + + this->residual_.resize(fvGeometry.numScv); + this->residual_ = 0; + + this->elemPtr_ = &element; + this->fvElemGeomPtr_ = &fvGeometry; + this->bcTypesPtr_ = &bcTypes; + this->prevVolVarsPtr_ = 0; + this->curVolVarsPtr_ = &volVars; + evalPhaseStorage_(phaseIdx); + } + + /*! + * \brief Evaluate the amount all conservation quantities + * (e.g. phase mass) within a sub-control volume. + * + * The result should be averaged over the volume (e.g. phase mass + * inside a sub control volume divided by the volume) + * + * \param storage the mass of the component 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]; + + // Compute storage term of all fluid components in the fluid phases + storage = 0; + for (unsigned int phaseIdx = 0; phaseIdx < numPhases /*+ numSPhases*/; ++phaseIdx) + { + //if(phaseIdx< numPhases) + //{ + for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) //H2O, Air, Salt + { + int eqIdx = conti0EqIdx + compIdx; + if (replaceCompEqIdx != eqIdx) + { + storage[eqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx) + * volVars.porosity(); + } + else + { + storage[replaceCompEqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.porosity(); + } + } + } + Valgrind::CheckDefined(storage); + } + /*! + * \brief Evaluates the total flux of all conservation quantities + * over a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fIdx The index of the sub-control-volume face + * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face + */ + void computeFlux(PrimaryVariables &flux, const int fIdx, bool onBoundary = false) const + { + FluxVariables fluxVars(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_(), + onBoundary); + + flux = 0; + asImp_()->computeAdvectiveFlux(flux, fluxVars); + asImp_()->computeDiffusiveFlux(flux, fluxVars); + Valgrind::CheckDefined(flux); + } + /*! + * \brief Evaluates the advective mass flux of all components 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 + //////// + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // 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)); + + for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) + { + // add advective flux of current component in current + // phase + unsigned int eqIdx = conti0EqIdx + compIdx; + + if (eqIdx != replaceCompEqIdx) + { + // upstream vertex + flux[eqIdx] += fluxVars.KmvpNormal(phaseIdx) + * (massUpwindWeight_ + * up.mobility(phaseIdx) + * up.molarDensity(phaseIdx) + * up.moleFraction(phaseIdx, compIdx) + + + (1.0 - massUpwindWeight_) + * dn.mobility(phaseIdx) + * dn.molarDensity(phaseIdx) + * dn.moleFraction(phaseIdx, compIdx)); + + Valgrind::CheckDefined(fluxVars.KmvpNormal(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + } + else + { + flux[replaceCompEqIdx] += fluxVars.KmvpNormal(phaseIdx) + * (massUpwindWeight_ + * up.molarDensity(phaseIdx) + * up.mobility(phaseIdx) + + + (1.0 - massUpwindWeight_) + * dn.molarDensity(phaseIdx) + * dn.mobility(phaseIdx)); + + + Valgrind::CheckDefined(fluxVars.KmvpNormal(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + } + } + } + } + + /*! + * \brief Evaluates the diffusive mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The 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 + { + //Loop calculates the diffusive flux for every component in a phase. The amount of moles of a component + //(eg Air in liquid) in a phase + //which is not the main component (eg. H2O in the liquid phase) moved from i to j equals the amount of moles moved + //from the main component in a phase (eg. H2O in the liquid phase) from j to i. So two fluxes in each component loop + // are calculated in the same phase. + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + //add diffusive fluxes only to the component balances + if (replaceCompEqIdx != (conti0EqIdx + compIdx)) + { + Scalar diffCont = - fluxVars.porousDiffCoeff(phaseIdx ,compIdx) + * fluxVars.molarDensity(phaseIdx) + * (fluxVars.moleFractionGrad(phaseIdx, compIdx) + * fluxVars.face().normal); + flux[conti0EqIdx + compIdx] += diffCont; + flux[conti0EqIdx + phaseIdx] -= diffCont; + } + } + } + +protected: + + void evalPhaseStorage_(int phaseIdx) + { + // evaluate the storage terms of a single phase + for (int i=0; i < this->fvGeometry_().numScv; i++) + { + PrimaryVariables &result = this->residual_[i]; + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[i]; + + // compute storage term of all fluid components within all phases + result = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + result[conti0EqIdx + compIdx] += volVars.density(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.massFraction(phaseIdx, compIdx) + * volVars.porosity(); + } + result *= this->fvGeometry_().subContVol[i].volume; + } + } + + Implementation *asImp_() + { return static_cast<Implementation *> (this); } + const Implementation *asImp_() const + { return static_cast<const Implementation *> (this); } + +public: + Scalar massUpwindWeight_; +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/model.hh b/dumux/porousmediumflow/2pnc/implicit/model.hh new file mode 100644 index 0000000000..7daf35faac --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/model.hh @@ -0,0 +1,741 @@ +// -*- 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 box scheme to the two-phase n-component flow model. +*/ + +#ifndef DUMUX_2PNC_MODEL_HH +#define DUMUX_2PNC_MODEL_HH + +#include <dumux/porousmediumflow/implicit/velocityoutput.hh> + +#include "properties.hh" +#include "indices.hh" +#include "localresidual.hh" + +namespace Dumux +{ +/*! + * \ingroup TwoPNCModel + * \brief Adaption of the fully implicit scheme to the + * two-phase n-component fully implicit model. + * + * This model implements two-phase n-component flow of two compressible and + * partially miscible fluids \f$\alpha \in \{ w, n \}\f$ composed of the n components + * \f$\kappa \in \{ w, a,\cdots \}\f$. The standard multiphase Darcy + * approach is used as the equation for the conservation of momentum: + * \f[ + v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} + \left(\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) + * \f] + * + * By inserting this into the equations for the conservation of the + * components, one gets one transport equation for each component + * \f{eqnarray} + && \phi \frac{\partial (\sum_\alpha \varrho_\alpha X_\alpha^\kappa S_\alpha )} + {\partial t} + - \sum_\alpha \text{div} \left\{ \varrho_\alpha X_\alpha^\kappa + \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} + (\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g}) \right\} + \nonumber \\ \nonumber \\ + &-& \sum_\alpha \text{div} \left\{{\bf D_{\alpha, pm}^\kappa} \varrho_{\alpha} \text{grad}\, X^\kappa_{\alpha} \right\} + - \sum_\alpha q_\alpha^\kappa = 0 \qquad \kappa \in \{w, a,\cdots \} \, , + \alpha \in \{w, g\} + \f} + * + * All equations are discretized using a vertex-centered finite volume (box) + * or cell-centered finite volume scheme (this is not done for 2pnc approach yet, however possible) as + * spatial and the implicit Euler method as time discretization. + * + * By using constitutive relations for the capillary pressure \f$p_c = + * p_n - p_w\f$ and relative permeability \f$k_{r\alpha}\f$ and taking + * advantage of the fact that \f$S_w + S_n = 1\f$ and \f$X^\kappa_w + X^\kappa_n = 1\f$, the number of + * unknowns can be reduced to number of components. + * + * The used primary variables are, like in the two-phase model, either \f$p_w\f$ and \f$S_n\f$ + * or \f$p_n\f$ and \f$S_w\f$. The formulation which ought to be used can be + * specified by setting the <tt>Formulation</tt> property to either + * TwoPTwoCIndices::pWsN or TwoPTwoCIndices::pNsW. By + * default, the model uses \f$p_w\f$ and \f$S_n\f$. + * + * Moreover, the second primary variable depends on the phase state, since a + * primary variable switch is included. The phase state is stored for all nodes + * of the system. The model is uses mole fractions. + *Following cases can be distinguished: + * <ul> + * <li> Both phases are present: The saturation is used (either \f$S_n\f$ or \f$S_w\f$, dependent on the chosen <tt>Formulation</tt>), + * as long as \f$ 0 < S_\alpha < 1\f$</li>. + * <li> Only wetting phase is present: The mass fraction of, e.g., air in the wetting phase \f$X^a_w\f$ is used, + * as long as the maximum mass fraction is not exceeded (\f$X^a_w<X^a_{w,max}\f$)</li> + * <li> Only non-wetting phase is present: The mass fraction of, e.g., water in the non-wetting phase, \f$X^w_n\f$, is used, + * as long as the maximum mass fraction is not exceeded (\f$X^w_n<X^w_{n,max}\f$)</li> + * </ul> + */ + +template<class TypeTag> +class TwoPNCModel: public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, BaseModel) ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum { dim = GridView::dimension }; + enum { dimWorld = GridView::dimensionworld }; + + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + enum { numComponents = GET_PROP_VALUE(TypeTag, NumComponents) }; + enum { numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents) }; + + enum { + pressureIdx = Indices::pressureIdx, + switchIdx = Indices::switchIdx + }; + enum { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx + }; + enum { + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx + }; + enum { + wPhaseOnly = Indices::wPhaseOnly, + nPhaseOnly = Indices::nPhaseOnly, + bothPhases = Indices::bothPhases + }; + enum { + plSg = TwoPNCFormulation::plSg, + pgSl = TwoPNCFormulation::pgSl, + formulation = GET_PROP_VALUE(TypeTag, Formulation) + }; + + typedef CompositionalFluidState<Scalar, FluidSystem> FluidState; + + typedef typename GridView::template Codim<dim>::Entity Vertex; + typedef typename GridView::template Codim<0>::Entity Element; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef typename GridView::ctype CoordScalar; + typedef Dune::FieldMatrix<CoordScalar, dimWorld, dimWorld> Tensor; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + +public: + /*! + * \brief Initialize the static data with the initial solution. + * + * \param problem The problem to be solved + */ + void init(Problem &problem) + { + ParentType::init(problem); + + unsigned numDofs = this->numDofs(); + + staticDat_.resize(numDofs); + + setSwitched_(false); + + for (const auto& element : Dune::elements(this->gridView_())) + { + if (!isBox) // i.e. cell-centered discretization + { + int dofIdxGlobal = this->dofMapper().index(element); + const GlobalPosition &globalPos = element.geometry().center(); + + // initialize phase presence + staticDat_[dofIdxGlobal].phasePresence + = this->problem_().initialPhasePresence(*(this->gridView_().template begin<dim>()), + dofIdxGlobal, globalPos); + staticDat_[dofIdxGlobal].wasSwitched = false; + + staticDat_[dofIdxGlobal].oldPhasePresence + = staticDat_[dofIdxGlobal].phasePresence; + } + } + + if (isBox) // i.e. vertex-centered discretization + { + for (const auto& vertex : Dune::vertices(this->gridView_())) + { + int dofIdxGlobal = this->dofMapper().index(vertex); + const GlobalPosition &globalPos = vertex.geometry().corner(0); + + // initialize phase presence + staticDat_[dofIdxGlobal].phasePresence + = this->problem_().initialPhasePresence(vertex, dofIdxGlobal, + globalPos); + staticDat_[dofIdxGlobal].wasSwitched = false; + + staticDat_[dofIdxGlobal].oldPhasePresence + = staticDat_[dofIdxGlobal].phasePresence; + } + } + } + + /*! + * \brief Compute the total storage of all conservation quantities in one phase + * + * \param storage Contains the storage of each component in one phase + * \param phaseIdx The phase index + */ + void globalPhaseStorage(PrimaryVariables &storage, int phaseIdx) + { + storage = 0; + + for (const auto& element : Dune::elements(this->gridView_())) + { + if(element.partitionType() == Dune::InteriorEntity) + { + this->localResidual().evalPhaseStorage(element, phaseIdx); + + for (unsigned int i = 0; i < this->localResidual().storageTerm().size(); ++i) + storage += this->localResidual().storageTerm()[i]; + } + } + + this->gridView_().comm().sum(storage); + } + + /*! + * \brief Called by the update() method if applying the newton + * method was unsuccessful. + */ + void updateFailed() + { + ParentType::updateFailed(); + + setSwitched_(false); + resetPhasePresence_(); + } + + /*! + * \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() + { + ParentType::advanceTimeLevel(); + + // update the phase state + updateOldPhasePresence_(); + setSwitched_(false); + } + + /*! + * \brief Return true if the primary variables were switched for + * at least one vertex after the last timestep. + */ + bool switched() const + { + return switchFlag_; + } + + /*! + * \brief Returns the phase presence of the current or the old solution of a vertex. + * + * \param globalVertexIdx The global vertex index + * \param oldSol Evaluate function with solution of current or previous time step + */ + int phasePresence(int globalVertexIdx, bool oldSol) const + { + return oldSol ? staticDat_[globalVertexIdx].oldPhasePresence + : staticDat_[globalVertexIdx].phasePresence; + } + + /*! + * \brief Append all quantities of interest which can be derived + * from the solution of the current time step to the VTK + * writer. + * + * \param sol The solution vector + * \param writer The writer for multi-file VTK datasets + */ + 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; + + // get the number of degrees of freedom + unsigned numDofs = this->numDofs(); + + ScalarField *Sg = writer.allocateManagedBuffer (numDofs); + ScalarField *Sl = writer.allocateManagedBuffer (numDofs); + ScalarField *pg = writer.allocateManagedBuffer (numDofs); + ScalarField *pl = writer.allocateManagedBuffer (numDofs); + ScalarField *pc = writer.allocateManagedBuffer (numDofs); + ScalarField *rhoL = writer.allocateManagedBuffer (numDofs); + ScalarField *rhoG = writer.allocateManagedBuffer (numDofs); + ScalarField *mobL = writer.allocateManagedBuffer (numDofs); + ScalarField *mobG = writer.allocateManagedBuffer (numDofs); + ScalarField *temperature = writer.allocateManagedBuffer (numDofs); + ScalarField *poro = writer.allocateManagedBuffer (numDofs); + ScalarField *boxVolume = writer.allocateManagedBuffer (numDofs); + VectorField *velocityN = writer.template allocateManagedBuffer<double, dim>(numDofs); + VectorField *velocityW = writer.template allocateManagedBuffer<double, dim>(numDofs); + ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + // initialize velocity fields + for (unsigned int i = 0; i < numDofs; ++i) + { + (*velocityN)[i] = Scalar(0); + (*velocityW)[i] = Scalar(0); + } + } + + ScalarField *moleFraction[numPhases][numComponents]; + for (int i = 0; i < numPhases; ++i) + for (int j = 0; j < numComponents; ++j) + moleFraction[i][j] = writer.allocateManagedBuffer(numDofs); + + ScalarField *molarity[numComponents]; + for (int j = 0; j < numComponents ; ++j) + molarity[j] = writer.allocateManagedBuffer(numDofs); + + ScalarField *Perm[dim]; + for (int j = 0; j < dim; ++j) //Permeability only in main directions xx and yy + Perm[j] = writer.allocateManagedBuffer(numDofs); + + *boxVolume = 0; + + unsigned numElements = this->gridView_().size(0); + ScalarField *rank = writer.allocateManagedBuffer (numElements); + + FVElementGeometry fvGeometry; + VolumeVariables volVars; + ElementVolumeVariables elemVolVars; + + for (const auto& element : Dune::elements(this->gridView_())) + { + int eIdxGlobal = this->problem_().elementMapper().index(element); + (*rank)[eIdxGlobal] = this->gridView_().comm().rank(); + fvGeometry.update(this->gridView_(), element); + + elemVolVars.update(this->problem_(), + element, + fvGeometry, + false /* oldSol? */); + + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); + + volVars.update(sol[dofIdxGlobal], + this->problem_(), + element, + fvGeometry, + scvIdx, + false); + + GlobalPosition globalPos = fvGeometry.subContVol[scvIdx].global; + (*Sg)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx); + (*Sl)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx); + (*pg)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx); + (*pl)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx); + (*pc)[dofIdxGlobal] = elemVolVars[scvIdx].capillaryPressure(); + (*rhoL)[dofIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx); + (*rhoG)[dofIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx); + (*mobL)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(wPhaseIdx); + (*mobG)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(nPhaseIdx); + (*boxVolume)[dofIdxGlobal] += fvGeometry.subContVol[scvIdx].volume; + (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity(); + (*temperature)[dofIdxGlobal] = elemVolVars[scvIdx].temperature(); + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + (*moleFraction[phaseIdx][compIdx])[dofIdxGlobal]= volVars.moleFraction(phaseIdx,compIdx); + Valgrind::CheckDefined((*moleFraction[phaseIdx][compIdx])[dofIdxGlobal]); + } + } + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + (*molarity[compIdx])[dofIdxGlobal] = (volVars.molarity(wPhaseIdx, compIdx)); + + Tensor K = perm_(this->problem_().spatialParams().intrinsicPermeability(element, fvGeometry, scvIdx)); + + for (int j = 0; j<dim; ++j) + (*Perm[j])[dofIdxGlobal] = K[j][j] /* volVars.permFactor()*/; + }; + + // velocity output + if(velocityOutput.enableOutput()){ + velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); + velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); + } + + } // loop over element + + writer.attachDofData(*Sg, "Sg", isBox); + writer.attachDofData(*Sl, "Sl", isBox); + writer.attachDofData(*pg, "pg", isBox); + writer.attachDofData(*pl, "pl", isBox); + writer.attachDofData(*pc, "pc", isBox); + writer.attachDofData(*rhoL, "rhoL", isBox); + writer.attachDofData(*rhoG, "rhoG", isBox); + writer.attachDofData(*mobL, "mobL", isBox); + writer.attachDofData(*mobG, "mobG", isBox); + writer.attachDofData(*poro, "porosity", isBox); + writer.attachDofData(*temperature, "temperature", isBox); + writer.attachDofData(*boxVolume, "boxVolume", isBox); + writer.attachDofData(*Perm[0], "Kxx", isBox); + if (dim >= 2) + writer.attachDofData(*Perm[1], "Kyy", isBox); + if (dim == 3) + writer.attachDofData(*Perm[2], "Kzz", isBox); + + for (int i = 0; i < numPhases; ++i) + { + for (int j = 0; j < numComponents; ++j) + { + std::ostringstream oss; + oss << "x" + << FluidSystem::componentName(j) + << FluidSystem::phaseName(i); + writer.attachDofData(*moleFraction[i][j], oss.str().c_str(), isBox); + } + } + + for (int j = 0; j < numComponents; ++j) + { + std::ostringstream oss; + oss << "m^w_" + << FluidSystem::componentName(j); + writer.attachDofData(*molarity[j], oss.str().c_str(), isBox); + } + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + writer.attachDofData(*velocityW, "velocityW", isBox, dim); + writer.attachDofData(*velocityN, "velocityN", isBox, dim); + } + + writer.attachCellData(*rank, "process rank"); + } + + /*! + * \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 + */ + template<class Entity> + void serializeEntity(std::ostream &outStream, const Entity &entity) + { + // write primary variables + ParentType::serializeEntity(outStream, entity); + int dofIdxGlobal = this->dofMapper().index(entity); + + if (!outStream.good()) + DUNE_THROW(Dune::IOError, "Could not serialize vertex " << dofIdxGlobal); + + outStream << staticDat_[dofIdxGlobal].phasePresence << " "; + } + + /*! + * \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 + */ + template<class Entity> + void deserializeEntity(std::istream &inStream, const Entity &entity) + { + // read primary variables + ParentType::deserializeEntity(inStream, entity); + int dofIdxGlobal = this->dofMapper().index(entity); + + if (!inStream.good()) + DUNE_THROW(Dune::IOError, + "Could not deserialize vertex " << dofIdxGlobal); + + inStream >> staticDat_[dofIdxGlobal].phasePresence; + staticDat_[dofIdxGlobal].oldPhasePresence + = staticDat_[dofIdxGlobal].phasePresence; + + } + + /*! + * \brief Update the static data of all vertices in the grid. + * + * \param curGlobalSol The current global solution + * \param oldGlobalSol The previous global solution + */ + void updateStaticData(SolutionVector &curGlobalSol, + const SolutionVector &oldGlobalSol) + { + bool wasSwitched = false; + + for (unsigned i = 0; i < staticDat_.size(); ++i) + staticDat_[i].visited = false; + + FVElementGeometry fvGeometry; + static VolumeVariables volVars; + for (const auto& element : Dune::elements(this->gridView_())) + { + fvGeometry.update(this->gridView_(), element); + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dim); + + if (staticDat_[dofIdxGlobal].visited) + continue; + + staticDat_[dofIdxGlobal].visited = true; + volVars.update(curGlobalSol[dofIdxGlobal], + this->problem_(), + element, + fvGeometry, + scvIdx, + false); + const GlobalPosition &global = element.geometry().corner(scvIdx); + if (primaryVarSwitch_(curGlobalSol, volVars, dofIdxGlobal, global)) + wasSwitched = true; + } + } + + // make sure that if there was a variable switch in an + // other partition we will also set the switch flag + // for our partition. + wasSwitched = this->gridView_().comm().max(wasSwitched); + + setSwitched_(wasSwitched); + } + +protected: + /*! + * \brief Data which is attached to each vertex and is not only + * stored locally. + */ + struct StaticVars + { + int phasePresence; + bool wasSwitched; + + int oldPhasePresence; + bool visited; + }; + + Tensor perm_(Scalar perm) + { + Tensor K(0.0); + + for(int i=0; i<dim; i++) + K[i][i] = perm; + + return K; + } + + Tensor perm_(Tensor perm) + { + return perm; + } + + /*! + * \brief Reset the current phase presence of all vertices to the old one. + * + * This is done after an update failed. + */ + void resetPhasePresence_() + { + int numDofs = this->gridView_().size(dim); + for (int i = 0; i < numDofs; ++i) + { + staticDat_[i].phasePresence + = staticDat_[i].oldPhasePresence; + staticDat_[i].wasSwitched = false; + } + } + + /*! + * \brief Set the old phase of all verts state to the current one. + */ + void updateOldPhasePresence_() + { + int numDofs = this->gridView_().size(dim); + for (int i = 0; i < numDofs; ++i) + { + staticDat_[i].oldPhasePresence + = staticDat_[i].phasePresence; + staticDat_[i].wasSwitched = false; + } + } + + /*! + * \brief Set whether there was a primary variable switch after in + * the last timestep. + */ + void setSwitched_(bool yesno) + { + switchFlag_ = yesno; + } + + // perform variable switch at a vertex; Returns true if a + // variable switch was performed. + bool primaryVarSwitch_(SolutionVector &globalSol, + const VolumeVariables &volVars, int dofIdxGlobal, + const GlobalPosition &globalPos) + { + + // evaluate primary variable switch + bool wouldSwitch = false; + int phasePresence = staticDat_[dofIdxGlobal].phasePresence; + int newPhasePresence = phasePresence; + + //check if a primary variable switch is necessary + if (phasePresence == bothPhases) + { + Scalar Smin = 0; //saturation threshold + if (staticDat_[dofIdxGlobal].wasSwitched) + Smin = -0.01; + + //if saturation of liquid phase is smaller 0 switch + if (volVars.saturation(wPhaseIdx) <= Smin) + { + wouldSwitch = true; + //liquid phase has to disappear + std::cout << "Liquid Phase disappears at vertex " << dofIdxGlobal + << ", coordinated: " << globalPos << ", Sl: " + << volVars.saturation(wPhaseIdx) << std::endl; + newPhasePresence = nPhaseOnly; + + //switch not depending on formulation + //switch "Sl" to "xgH20" + globalSol[dofIdxGlobal][switchIdx] + = volVars.moleFraction(nPhaseIdx, wCompIdx /*H2O*/); + + //switch all secondary components to mole fraction in gas phase + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + globalSol[dofIdxGlobal][compIdx] = volVars.moleFraction(nPhaseIdx,compIdx); + } + //if saturation of gas phase is smaller than 0 switch + else if (volVars.saturation(nPhaseIdx) <= Smin) + { + wouldSwitch = true; + //gas phase has to disappear + std::cout << "Gas Phase disappears at vertex " << dofIdxGlobal + << ", coordinated: " << globalPos << ", Sg: " + << volVars.saturation(nPhaseIdx) << std::endl; + newPhasePresence = wPhaseOnly; + + //switch "Sl" to "xlN2" + globalSol[dofIdxGlobal][switchIdx] + = volVars.moleFraction(wPhaseIdx, nCompIdx /*N2*/); + } + } + else if (phasePresence == nPhaseOnly) + { + Scalar xlmax = 1; + Scalar sumxl = 0; + //Calculate sum of mole fractions in the hypothetical liquid phase + for (int compIdx = 0; compIdx < numComponents; compIdx++) + { + sumxl += volVars.moleFraction(wPhaseIdx, compIdx); + } + if (sumxl > xlmax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xlmax *=1.02; + //liquid phase appears if sum is larger than one + if (sumxl/*sum of mole fractions*/ > xlmax/*1*/) + { + std::cout << "Liquid Phase appears at vertex " << dofIdxGlobal + << ", coordinated: " << globalPos << ", sumxl: " + << sumxl << std::endl; + newPhasePresence = bothPhases; + + //saturation of the liquid phase set to 0.0001 (if formulation pgSl and vice versa) + if (formulation == pgSl) + globalSol[dofIdxGlobal][switchIdx] = 0.0001; + else if (formulation == plSg) + globalSol[dofIdxGlobal][switchIdx] = 0.9999; + + //switch all secondary components back to liquid mole fraction + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + globalSol[dofIdxGlobal][compIdx] = volVars.moleFraction(wPhaseIdx,compIdx); + } + } + else if (phasePresence == wPhaseOnly) + { + Scalar xgmax = 1; + Scalar sumxg = 0; + //Calculate sum of mole fractions in the hypothetical liquid phase + for (int compIdx = 0; compIdx < numComponents; compIdx++) + { + sumxg += volVars.moleFraction(nPhaseIdx, compIdx); + } + if (sumxg > xgmax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xgmax *=1.02; + //liquid phase appears if sum is larger than one + if (sumxg > xgmax) + { + std::cout << "Gas Phase appears at vertex " << dofIdxGlobal + << ", coordinated: " << globalPos << ", sumxg: " + << sumxg << std::endl; + newPhasePresence = bothPhases; + //saturation of the liquid phase set to 0.9999 (if formulation pgSl and vice versa) + if (formulation == pgSl) + globalSol[dofIdxGlobal][switchIdx] = 0.9999; + else if (formulation == plSg) + globalSol[dofIdxGlobal][switchIdx] = 0.0001; + + } + } + + + staticDat_[dofIdxGlobal].phasePresence = newPhasePresence; + staticDat_[dofIdxGlobal].wasSwitched = wouldSwitch; + return phasePresence != newPhasePresence; + } + + // parameters given in constructor + std::vector<StaticVars> staticDat_; + bool switchFlag_; +}; + +} + +#include "propertydefaults.hh" + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/newtoncontroller.hh b/dumux/porousmediumflow/2pnc/implicit/newtoncontroller.hh new file mode 100644 index 0000000000..d5a41740fc --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/newtoncontroller.hh @@ -0,0 +1,105 @@ +// -*- 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 A two-phase n-component specific controller for the newton solver. + */ +#ifndef DUMUX_2PNC_NEWTON_CONTROLLER_HH +#define DUMUX_2PNC_NEWTON_CONTROLLER_HH + +#include "properties.hh" + +#include <dumux/nonlinear/newtoncontroller.hh> + +namespace Dumux { +/*! + * \ingroup Newton + * \ingroup TwoPNCModel + * \brief A two-phase n-component 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. + */ +template <class TypeTag> +class TwoPNCNewtonController : public NewtonController<TypeTag> +{ + typedef NewtonController<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(Problem)) Problem; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(SolutionVector)) SolutionVector; + +public: + TwoPNCNewtonController(Problem &problem) + : ParentType(problem) + {}; + + + /*! + * \brief + * Suggest a new time step size based either on the number of newton + * iterations required or on the variable switch + * + * \param uCurrentIter The current global solution vector + * \param uLastIter The previous global solution vector + * + */ + void newtonEndStep(SolutionVector &uCurrentIter, + const SolutionVector &uLastIter) + { + int succeeded; + try { + // call the method of the base class + this->method().model().updateStaticData(uCurrentIter, uLastIter); + ParentType::newtonEndStep(uCurrentIter, uLastIter); + + succeeded = 1; + if (this->gridView_().comm().size() > 1) + succeeded = this->gridView_().comm().min(succeeded); + } + catch (Dumux::NumericalProblem &e) + { + std::cout << "rank " << this->problem_().gridView().comm().rank() + << " caught an exception while updating:" << e.what() + << "\n"; + succeeded = 0; + if (this->gridView_().comm().size() > 1) + succeeded = this->gridView_().comm().min(succeeded); + } + + if (!succeeded) { + DUNE_THROW(NumericalProblem, + "A process did not succeed in linearizing the system"); + } + } + + /*! + * \brief Returns true if the current solution can be considered to + * be accurate enough + */ + bool newtonConverged() + { + if (this->method().model().switched()) + return false; + + return ParentType::newtonConverged(); + } +}; +} + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/properties.hh b/dumux/porousmediumflow/2pnc/implicit/properties.hh new file mode 100644 index 0000000000..44e495060a --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/properties.hh @@ -0,0 +1,82 @@ +// -*- 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 TwoPNCModel + * + * \file + * + * \brief Defines the properties required for the two-phase n-component + * fully implicit model. + */ +#ifndef DUMUX_2PNC_PROPERTIES_HH +#define DUMUX_2PNC_PROPERTIES_HH + +#include <dumux/implicit/box/properties.hh> +#include <dumux/implicit/cellcentered/properties.hh> +#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> + +namespace Dumux +{ + +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tag for the implicit isothermal two phase n component problems +NEW_TYPE_TAG(TwoPNC); +NEW_TYPE_TAG(BoxTwoPNC, INHERITS_FROM(BoxModel, TwoPNC)); +NEW_TYPE_TAG(CCTwoPNC, INHERITS_FROM(CCModel, TwoPNC)); + +//! The type tag for the implicit non-isothermal two phase n component problems +NEW_TYPE_TAG(TwoPNCNI, INHERITS_FROM(TwoPNC, NonIsothermal)); +NEW_TYPE_TAG(BoxTwoPNCNI, INHERITS_FROM(BoxModel, TwoPNCNI)); +NEW_TYPE_TAG(CCTwoPNCNI, INHERITS_FROM(CCModel, TwoPNCNI)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system +NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system +NEW_PROP_TAG(NumMajorComponents); //!< Number of major fluid components which are considered in the calculation of the phase density +NEW_PROP_TAG(TwoPNCIndices); //!< Enumerations for the 2pncMin models +NEW_PROP_TAG(Formulation); //!< The formulation of the model +NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters +NEW_PROP_TAG(FluidSystem); //!< Type of the multi-component relations +NEW_PROP_TAG(FluidState); //!< Type of the fluid state of the 2pnc model +NEW_PROP_TAG(Indices); //!< Enumerations for the model +NEW_PROP_TAG(Chemistry); //!< The chemistry class with which solves equlibrium reactions + +NEW_PROP_TAG(MaterialLaw); //!< The material law which ought to be used (extracted from the spatial parameters) +NEW_PROP_TAG(MaterialLawParams); //!< The parameters of the material law (extracted from the spatial parameters) + +NEW_PROP_TAG(ReplaceCompEqIdx); //!< The index of the total mass balance equation, if one component balance is replaced (ReplaceCompEqIdx < NumComponents) +NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output +NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem +NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The value of the upwind weight for the mass conservation equations +NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< The value of the upwind parameter for the mobility +NEW_PROP_TAG(BaseFluxVariables); //! The base flux variables +} +} + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/propertydefaults.hh b/dumux/porousmediumflow/2pnc/implicit/propertydefaults.hh new file mode 100644 index 0000000000..753d77bea2 --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/propertydefaults.hh @@ -0,0 +1,225 @@ +// -*- 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 TwoPNCModel + * \file + * + * \brief Defines default values for most properties required by the + * two-phase n-component fully implicit model. + */ +#ifndef DUMUX_2PNC_PROPERTY_DEFAULTS_HH +#define DUMUX_2PNC_PROPERTY_DEFAULTS_HH + +#include "indices.hh" +#include "model.hh" +#include "fluxvariables.hh" +#include "volumevariables.hh" +#include "properties.hh" +#include "newtoncontroller.hh" + +#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> +#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> +#include <dumux/material/spatialparams/implicitspatialparams.hh> +#include <dumux/material/fluidmatrixinteractions/2p/thermalconductivitysomerton.hh> + +namespace Dumux +{ + +namespace Properties { +////////////////////////////////////////////////////////////////// +// Property values +////////////////////////////////////////////////////////////////// + +/*! + * \brief Set the property for the number of components. + * + * We just forward the number from the fluid system + * + */ +SET_PROP(TwoPNC, NumComponents) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numComponents; + +}; +//! Set as default that no component mass balance is replaced by the total mass balance +SET_PROP(TwoPNC, ReplaceCompEqIdx) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numComponents; +}; +//! The major components belonging to the existing phases are mentioned here e.g., 2 for water and air being the major component in the liquid and gas phases in a 2 phase system +SET_PROP(TwoPNC, NumMajorComponents) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numPhases; + static_assert(value == 2, + "The model is restricted to two-phases, thus number of major components must also be two."); +}; + +/*! + * \brief Set the property for the number of fluid phases. + * + * We just forward the number from the fluid system and use an static + * assert to make sure it is 2. + */ +SET_PROP(TwoPNC, NumPhases) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numPhases; + static_assert(value == 2, + "Only fluid systems with 2 fluid phases are supported by the 2p-nc model!"); +}; +/*! + * \brief Set the property for the number of equations: For each existing component one equation has to be solved. + */ +SET_PROP(TwoPNC, NumEq) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numComponents; +}; + +/*! + * \brief The fluid state which is used by the volume variables to + * store the thermodynamic state. This should be chosen + * appropriately for the model ((non-)isothermal, equilibrium, ...). + * This can be done in the problem. + */ +SET_PROP(TwoPNC, 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 the default formulation to pl-Sg: This can be over written in the problem. +SET_INT_PROP(TwoPNC, Formulation, TwoPNCFormulation::plSg); + +//! Set the property for the material parameters by extracting it from the material law. +SET_PROP(TwoPNC, MaterialLawParams) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(MaterialLaw)) MaterialLaw; + +public: + typedef typename MaterialLaw::Params type; +}; + +//! Use the 2pnc local residual +SET_TYPE_PROP(TwoPNC, LocalResidual, TwoPNCLocalResidual<TypeTag>); + +//! Use the 2pnc newton controller +SET_TYPE_PROP(TwoPNC, NewtonController, TwoPNCNewtonController<TypeTag>); + +//! the Model property +SET_TYPE_PROP(TwoPNC, Model, TwoPNCModel<TypeTag>); + +//! the VolumeVariables property +SET_TYPE_PROP(TwoPNC, VolumeVariables, TwoPNCVolumeVariables<TypeTag>); + +//! the FluxVariables property +SET_TYPE_PROP(TwoPNC, FluxVariables, TwoPNCFluxVariables<TypeTag>); + +//! define the base flux variables to realize Darcy flow +SET_TYPE_PROP(TwoPNC, BaseFluxVariables, ImplicitDarcyFluxVariables<TypeTag>); + +//! the upwind weight for the mass conservation equations. +SET_SCALAR_PROP(TwoPNC, ImplicitMassUpwindWeight, 1.0); + +//! Set default mobility upwind weight to 1.0, i.e. fully upwind +SET_SCALAR_PROP(TwoPNC, ImplicitMobilityUpwindWeight, 1.0); + +//! The indices required by the isothermal 2pnc model +SET_TYPE_PROP(TwoPNC, Indices, TwoPNCIndices <TypeTag, /*PVOffset=*/0>); + +//! Use the ImplicitSpatialParams by default +SET_TYPE_PROP(TwoPNC, SpatialParams, ImplicitSpatialParams<TypeTag>); + +//! Enable gravity by default +SET_BOOL_PROP(TwoPNC, ProblemEnableGravity, true); + +//! Disable velocity output by default +SET_BOOL_PROP(TwoPNC, VtkAddVelocity, false); + +//! Somerton is used as default model to compute the effective thermal heat conductivity +SET_PROP(TwoPNCNI, ThermalConductivityModel) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; +public: + typedef ThermalConductivitySomerton<Scalar, Indices> type; +}; + +//! temperature is already written by the isothermal model +SET_BOOL_PROP(TwoPNCNI, NiOutputLevel, 0); + +////////////////////////////////////////////////////////////////// +// Property values for isothermal model required for the general non-isothermal model +////////////////////////////////////////////////////////////////// + +// set isothermal Model +SET_TYPE_PROP(TwoPNCNI, IsothermalModel, TwoPNCModel<TypeTag>); + +// set isothermal FluxVariables +SET_TYPE_PROP(TwoPNCNI, IsothermalFluxVariables, TwoPNCFluxVariables<TypeTag>); + +//set isothermal VolumeVariables +SET_TYPE_PROP(TwoPNCNI, IsothermalVolumeVariables, TwoPNCVolumeVariables<TypeTag>); + +//set isothermal LocalResidual +SET_TYPE_PROP(TwoPNCNI, IsothermalLocalResidual, TwoPNCLocalResidual<TypeTag>); + +//set isothermal Indices +SET_TYPE_PROP(TwoPNCNI, IsothermalIndices, TwoPNCIndices<TypeTag, /*PVOffset=*/0>); + +//set isothermal NumEq +SET_PROP(TwoPNCNI, IsothermalNumEq) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numComponents; +}; + + +} + +} + +#endif diff --git a/dumux/porousmediumflow/2pnc/implicit/volumevariables.hh b/dumux/porousmediumflow/2pnc/implicit/volumevariables.hh new file mode 100644 index 0000000000..27e1a4f229 --- /dev/null +++ b/dumux/porousmediumflow/2pnc/implicit/volumevariables.hh @@ -0,0 +1,529 @@ +// -*- 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 Contains the quantities which are constant within a + * finite volume in the two-phase, n-component model. + */ +#ifndef DUMUX_2PNC_VOLUME_VARIABLES_HH +#define DUMUX_2PNC_VOLUME_VARIABLES_HH + +#include <iostream> +#include <vector> + +#include <dumux/implicit/model.hh> +#include <dumux/material/fluidstates/compositionalfluidstate.hh> +#include <dumux/common/math.hh> + +#include "properties.hh" +#include "indices.hh" +#include <dumux/material/constraintsolvers/computefromreferencephase2pnc.hh> +#include <dumux/material/constraintsolvers/miscible2pnccomposition.hh> + +namespace Dumux +{ + +/*! + * \ingroup TwoPNCModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are are constant within a + * finite volume in the two-phase, n-component model. + */ +template <class TypeTag> +class TwoPNCVolumeVariables : public ImplicitVolumeVariables<TypeTag> +{ + typedef ImplicitVolumeVariables<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum + { + dim = GridView::dimension, + dimWorld=GridView::dimensionworld, + + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents), + + // formulations + formulation = GET_PROP_VALUE(TypeTag, Formulation), + plSg = TwoPNCFormulation::plSg, + pgSl = TwoPNCFormulation::pgSl, + + // phase indices + wPhaseIdx = FluidSystem::wPhaseIdx, + nPhaseIdx = FluidSystem::nPhaseIdx, + + // component indices + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx, + + // phase presence enums + nPhaseOnly = Indices::nPhaseOnly, + wPhaseOnly = Indices::wPhaseOnly, + bothPhases = Indices::bothPhases, + + // primary variable indices + pressureIdx = Indices::pressureIdx, + switchIdx = Indices::switchIdx, + + }; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename Grid::ctype CoordScalar; + typedef Dumux::Miscible2pNCComposition<Scalar, FluidSystem> Miscible2pNCComposition; + typedef Dumux::ComputeFromReferencePhase2pNC<Scalar, FluidSystem> ComputeFromReferencePhase2pNC; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; +public: + + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; + + /*! + * \copydoc ImplicitVolumeVariables::update + * \param primaryVariables The primary Variables + */ + void update(const PrimaryVariables &primaryVariables, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx, + bool isOldSol) + { + ParentType::update(primaryVariables, + problem, + element, + fvGeometry, + scvIdx, + isOldSol); + + completeFluidState(primaryVariables, problem, element, fvGeometry, scvIdx, fluidState_, isOldSol); + + ///////////// + // calculate the remaining quantities + ///////////// + const MaterialLawParams &materialParams = problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); + + // Second instance of a parameter cache. + // Could be avoided if diffusion coefficients also + // became part of the fluid state. + typename FluidSystem::ParameterCache paramCache; + paramCache.updateAll(fluidState_); + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + {// relative permeabilities + Scalar kr; + if (phaseIdx == wPhaseIdx) + kr = MaterialLaw::krw(materialParams, saturation(wPhaseIdx)); + else // ATTENTION: krn requires the liquid saturation + // as parameter! + kr = MaterialLaw::krn(materialParams, saturation(wPhaseIdx)); + mobility_[phaseIdx] = kr / fluidState_.viscosity(phaseIdx); + Valgrind::CheckDefined(mobility_[phaseIdx]); + int compIIdx = phaseIdx; + for(int compIdx = 0; compIdx < numComponents; ++compIdx) + { + int compJIdx = compIdx; + // binary diffusion coefficents + diffCoeff_[phaseIdx][compIdx] = 0.0; + if(compIIdx!= compJIdx) + diffCoeff_[phaseIdx][compIdx] = FluidSystem::binaryDiffusionCoefficient(fluidState_, + paramCache, + phaseIdx, + compIIdx, + compJIdx); + Valgrind::CheckDefined(diffCoeff_[phaseIdx][compIdx]); + } + } + + // porosity + porosity_ = problem.spatialParams().porosity(element, + fvGeometry, + scvIdx); + Valgrind::CheckDefined(porosity_); + // energy related quantities not contained in the fluid state + + asImp_().updateEnergy_(primaryVariables, problem,element, fvGeometry, scvIdx, isOldSol); + } + + /*! + * \copydoc ImplicitModel::completeFluidState + * \param isOldSol Specifies whether this is the previous solution or the current one + * \param primaryVariables The primary Variables + */ + static void completeFluidState(const PrimaryVariables& primaryVariables, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + int scvIdx, + FluidState& fluidState, + bool isOldSol = false) + + { + Scalar t = Implementation::temperature_(primaryVariables, problem, element, + fvGeometry, scvIdx); + fluidState.setTemperature(t); + + int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); + int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); + + ///////////// + // set the saturations + ///////////// + + Scalar Sg; + if (phasePresence == nPhaseOnly) + Sg = 1.0; + else if (phasePresence == wPhaseOnly) { + Sg = 0.0; + } + else if (phasePresence == bothPhases) { + if (formulation == plSg) + Sg = primaryVariables[switchIdx]; + else if (formulation == pgSl) + Sg = 1.0 - primaryVariables[switchIdx]; + else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); + } + else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); + fluidState.setSaturation(nPhaseIdx, Sg); + fluidState.setSaturation(wPhaseIdx, 1.0 - Sg); + + ///////////// + // set the pressures of the fluid phases + ///////////// + + // calculate capillary pressure + const MaterialLawParams &materialParams + = problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); + Scalar pc = MaterialLaw::pc(materialParams, 1 - Sg); + + // extract the pressures + if (formulation == plSg) { + fluidState.setPressure(wPhaseIdx, primaryVariables[pressureIdx]); + if (primaryVariables[pressureIdx] + pc < 0.0) + DUNE_THROW(Dumux::NumericalProblem,"Capillary pressure is too low"); + fluidState.setPressure(nPhaseIdx, primaryVariables[pressureIdx] + pc); + } + else if (formulation == pgSl) { + fluidState.setPressure(nPhaseIdx, primaryVariables[pressureIdx]); + // Here we check for (p_g - pc) in order to ensure that (p_l > 0) + if (primaryVariables[pressureIdx] - pc < 0.0) + { + std::cout<< "p_g: "<< primaryVariables[pressureIdx]<<" Cap_press: "<< pc << std::endl; + DUNE_THROW(Dumux::NumericalProblem,"Capillary pressure is too high"); + } + fluidState.setPressure(wPhaseIdx, primaryVariables[pressureIdx] - pc); + } + else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); + + ///////////// + // calculate the phase compositions + ///////////// + + typename FluidSystem::ParameterCache paramCache; + + // now comes the tricky part: calculate phase composition + if (phasePresence == bothPhases) { + // both phases are present, phase composition results from + // the gas <-> liquid equilibrium. This is + // the job of the "MiscibleMultiPhaseComposition" + // constraint solver + + // set the known mole fractions in the fluidState so that they + // can be used by the Miscible2pNCComposition constraint solver + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + { + fluidState.setMoleFraction(wPhaseIdx, compIdx, primaryVariables[compIdx]); + } + + Miscible2pNCComposition::solve(fluidState, + paramCache, + wPhaseIdx, //known phaseIdx + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + else if (phasePresence == nPhaseOnly){ + + Dune::FieldVector<Scalar, numComponents> moleFrac; + + + moleFrac[wCompIdx] = primaryVariables[switchIdx]; + + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + moleFrac[compIdx] = primaryVariables[compIdx]; + + + Scalar sumMoleFracNotGas = 0; + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + sumMoleFracNotGas+=moleFrac[compIdx]; + + sumMoleFracNotGas += moleFrac[wCompIdx]; + moleFrac[nCompIdx] = 1 - sumMoleFracNotGas; + + + // Set fluid state mole fractions + for (int compIdx=0; compIdx<numComponents; ++compIdx) + fluidState.setMoleFraction(nPhaseIdx, compIdx, moleFrac[compIdx]); + + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase2pNC" constraint solver + ComputeFromReferencePhase2pNC::solve(fluidState, + paramCache, + nPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + + } + else if (phasePresence == wPhaseOnly){ + // only the liquid phase is present, i.e. liquid phase + // composition is stored explicitly. + // extract _mass_ fractions in the gas phase + Dune::FieldVector<Scalar, numComponents> moleFrac; + + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + { + moleFrac[compIdx] = primaryVariables[compIdx]; + } + moleFrac[nCompIdx] = primaryVariables[switchIdx]; + Scalar sumMoleFracNotWater = 0; + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + { + sumMoleFracNotWater+=moleFrac[compIdx]; + } + sumMoleFracNotWater += moleFrac[nCompIdx]; + moleFrac[wCompIdx] = 1 -sumMoleFracNotWater; + + + // convert mass to mole fractions and set the fluid state + for (int compIdx=0; compIdx<numComponents; ++compIdx) + { + fluidState.setMoleFraction(wPhaseIdx, compIdx, moleFrac[compIdx]); + } + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase2pNC" constraint solver + ComputeFromReferencePhase2pNC::solve(fluidState, + paramCache, + wPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + paramCache.updateAll(fluidState); + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx); + Scalar mu = FluidSystem::viscosity(fluidState, paramCache, phaseIdx); + + fluidState.setDensity(phaseIdx, rho); + fluidState.setViscosity(phaseIdx, mu); + } + } + + /*! + * \brief Returns the phase state for the control-volume. + */ + const FluidState &fluidState() const + { return fluidState_; } + + /*! + * \brief Returns the saturation of a given phase within + * the control volume in \f$[-]\f$. + * + * \param phaseIdx The phase index + */ + Scalar saturation(int phaseIdx) const + { return fluidState_.saturation(phaseIdx); } + + /*! + * \brief Returns the mass density of a given phase within the + * control volume. + * + * \param phaseIdx The phase index + */ + Scalar density(int phaseIdx) const + { + if (phaseIdx < numPhases) + return fluidState_.density(phaseIdx); + + else + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + /*! + * \brief Returns the mass density of a given phase within the + * control volume. + * + * \param phaseIdx The phase index + */ + Scalar molarDensity(int phaseIdx) const + { + if (phaseIdx < numPhases) + return fluidState_.molarDensity(phaseIdx); + + else + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + /*! + * \brief Returns the effective pressure of a given phase within + * the control volume. + * + * \param phaseIdx The phase index + */ + Scalar pressure(int phaseIdx) const + { + return fluidState_.pressure(phaseIdx); + } + + /*! + * \brief Returns temperature inside the sub-control volume. + * + * Note that we assume thermodynamic equilibrium, i.e. the + * temperature of the rock matrix and of all fluid phases are + * identical. + */ + Scalar temperature() const + { return fluidState_.temperature(/*phaseIdx=*/0); } + + /*! + * \brief Returns the effective mobility of a given phase within + * the control volume. + * + * \param phaseIdx The phase index + */ + Scalar mobility(int phaseIdx) const + { + return mobility_[phaseIdx]; + } + + /*! + * \brief Returns the effective capillary pressure within the control volume + * in \f$[kg/(m*s^2)=N/m^2=Pa]\f$. + */ + Scalar capillaryPressure() const + { return fluidState_.pressure(FluidSystem::nPhaseIdx) - fluidState_.pressure(FluidSystem::wPhaseIdx); } + + /*! + * \brief Returns the average porosity within the control volume. + */ + Scalar porosity() const + { return porosity_; } + + + /*! + * \brief Returns the binary diffusion coefficients for a phase in \f$[m^2/s]\f$. + */ + Scalar diffCoeff(int phaseIdx, int compIdx) const + { return diffCoeff_[phaseIdx][compIdx]; } + + /*! + * \brief Returns the molarity of a component in the phase + * + * \param phaseIdx the index of the fluid phase + * \param compIdx the index of the component + */ + Scalar molarity(int phaseIdx, int compIdx) const // [moles/m^3] + { return this->fluidState_.molarity(phaseIdx, compIdx);} + + /*! + * \brief Returns the mass fraction of a component in the phase + * + * \param phaseIdx the index of the fluid phase + * \param compIdx the index of the component + */ + Scalar massFraction(int phaseIdx, int compIdx) const + { + return this->fluidState_.massFraction(phaseIdx, compIdx); + } + + /*! + * \brief Returns the mole fraction of a component in the phase + * + * \param phaseIdx the index of the fluid phase + * \param compIdx the index of the component + */ + Scalar moleFraction(int phaseIdx, int compIdx) const + { + return this->fluidState_.moleFraction(phaseIdx, compIdx); + } + +protected: + + static Scalar temperature_(const PrimaryVariables &priVars, + const Problem& problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx) + { + return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); + } + + template<class ParameterCache> + static Scalar enthalpy_(const FluidState& fluidState, + const ParameterCache& paramCache, + int phaseIdx) + { + return 0; + } + + /*! + * \brief Called by update() to compute the energy related quantities + */ + void updateEnergy_(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx, + bool isOldSol) + { }; + + Scalar porosity_; //!< Effective porosity within the control volume + Scalar mobility_[numPhases]; //!< Effective mobility within the control volume + Scalar density_; + FluidState fluidState_; + Scalar theta_; + Scalar InitialPorosity_; + Scalar molWtPhase_[numPhases]; + Dune::FieldMatrix<Scalar, numPhases, numComponents> diffCoeff_; + +private: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } + +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2pncmin/implicit/fluxvariables.hh b/dumux/porousmediumflow/2pncmin/implicit/fluxvariables.hh new file mode 100644 index 0000000000..8a87062691 --- /dev/null +++ b/dumux/porousmediumflow/2pncmin/implicit/fluxvariables.hh @@ -0,0 +1,162 @@ +// -**- 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 Contains the data which is required to calculate + * all fluxes of components over a face of a finite volume for + * the two-phase two-component mineralization model fully implicit model. + */ +#ifndef DUMUX_2PNCMIN_FLUX_VARIABLES_HH +#define DUMUX_2PNCMIN_FLUX_VARIABLES_HH + +#include <dumux/common/math.hh> +#include <dumux/common/spline.hh> +#include <dumux/porousmediumflow/2pnc/implicit/fluxvariables.hh> +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup TwoPNCMinModel + * \ingroup ImplicitFluxVariables + * \brief Contains the data which is required to calculate + * all fluxes of components over a face of a finite volume for + * the two-phase n-component mineralization fully implicit model. + * + * This means pressure and concentration gradients, phase densities at + * the integration point, etc. + */ + +template <class TypeTag> +class TwoPNCMinFluxVariables : public TwoPNCFluxVariables<TypeTag> +{ + typedef TwoPNCFluxVariables<TypeTag> ParentType; + typedef TwoPNCMinFluxVariables<TypeTag> ThisType; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + + typedef typename GridView::ctype CoordScalar; + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + + enum { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + }; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename FVElementGeometry::SubControlVolume SCV; + typedef typename FVElementGeometry::SubControlVolumeFace SCVFace; + + typedef Dune::FieldVector<CoordScalar, dimWorld> DimVector; + typedef Dune::FieldMatrix<CoordScalar, dim, dim> DimMatrix; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + wPhaseIdx = FluidSystem::wPhaseIdx, + nPhaseIdx = FluidSystem::nPhaseIdx, + wCompIdx = FluidSystem::wCompIdx, + }; + +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 sub-control-volume face + * \param elemVolVars The volume variables of the current element + * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face + */ + TwoPNCMinFluxVariables(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : ParentType(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) + { + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + this->density_[phaseIdx] = Scalar(0); + this->molarDensity_[phaseIdx] = Scalar(0); + this->potentialGrad_[phaseIdx] = Scalar(0); + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + this->massFractionGrad_[phaseIdx][compIdx] = Scalar(0); + this->moleFractionGrad_[phaseIdx][compIdx] = Scalar(0); + } + } + this->calculateGradients_(problem, element, elemVolVars); + this->calculateVelocities_(problem, element, elemVolVars); + this->calculateporousDiffCoeff_(problem, element, elemVolVars); + }; + +protected: + void calculateVelocities_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + const SpatialParams &spatialParams = problem.spatialParams(); + // multiply the pressure potential with the intrinsic permeability + DimMatrix K(0.0); + + for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) + { + const VolumeVariables &volVarsI = elemVolVars[this->face().i]; + const VolumeVariables &volVarsJ = elemVolVars[this->face().j]; + + auto K_i = spatialParams.intrinsicPermeability(element,this->fvGeometry_,this->face().i); + K_i *= volVarsI.permeabilityFactor(); + + auto K_j = spatialParams.intrinsicPermeability(element,this->fvGeometry_,this->face().j); + K_j *= volVarsJ.permeabilityFactor(); + + spatialParams.meanK(K,K_i,K_j); + + K.mv(this->potentialGrad_[phaseIdx], this->Kmvp_[phaseIdx]); + this->KmvpNormal_[phaseIdx] = - (this->Kmvp_[phaseIdx] * this->face().normal); + } + + // set the upstream and downstream vertices + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + this->upstreamIdx_[phaseIdx] = this->face().i; + this->downstreamIdx_[phaseIdx] = this->face().j; + + if (this->KmvpNormal_[phaseIdx] < 0) { + std::swap(this->upstreamIdx_[phaseIdx], + this->downstreamIdx_[phaseIdx]); + } + } + } +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2pncmin/implicit/indices.hh b/dumux/porousmediumflow/2pncmin/implicit/indices.hh new file mode 100644 index 0000000000..eac1763171 --- /dev/null +++ b/dumux/porousmediumflow/2pncmin/implicit/indices.hh @@ -0,0 +1,48 @@ +// -*- 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 indices required for the two-phase n-component mineralization + * fully implicit model. + */ +#ifndef DUMUX_2PNCMIN_INDICES_HH +#define DUMUX_2PNCMIN_INDICES_HH + +#include <dumux/porousmediumflow/2pnc/implicit/indices.hh> + +namespace Dumux +{ +/*! + * \ingroup TwoPNCMinModel + * \ingroup ImplicitIndices + * \brief The indices for the isothermal two-phase n-component mineralization model. + * + * \tparam PVOffset The first index in a primary variable vector. + */ +template <class TypeTag, int PVOffset = 0> + class TwoPNCMinIndices: public TwoPNCIndices<TypeTag, PVOffset> +{ +}; + +// \} + +} + +#endif diff --git a/dumux/porousmediumflow/2pncmin/implicit/localresidual.hh b/dumux/porousmediumflow/2pncmin/implicit/localresidual.hh new file mode 100644 index 0000000000..638ef7d391 --- /dev/null +++ b/dumux/porousmediumflow/2pncmin/implicit/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 of the Jacobian matrix for problems + * using the two-phase n-component mineralisation box model. + */ + +#ifndef DUMUX_2PNCMIN_LOCAL_RESIDUAL_BASE_HH +#define DUMUX_2PNCMIN_LOCAL_RESIDUAL_BASE_HH + +#include "properties.hh" +#include <dumux/porousmediumflow/2pnc/implicit/localresidual.hh> + +namespace Dumux +{ +/*! + * \ingroup TwoPNCMinModel + * \ingroup ImplicitLocalResidual + * \brief Element-wise calculation of the Jacobian matrix for problems + * using the two-phase n-component mineralization fully implicit box model. + * + * This class is used to fill the gaps in ImplicitLocalResidual for the two-phase n-component flow. + */ +template<class TypeTag> +class TwoPNCMinLocalResidual: public TwoPNCLocalResidual<TypeTag> +{ +protected: + typedef TwoPNCLocalResidual<TypeTag> ParentType; + typedef TwoPNCMinLocalResidual<TypeTag> ThisType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + + + enum + { + numEq = GET_PROP_VALUE(TypeTag, NumEq), + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numSPhases = GET_PROP_VALUE(TypeTag, NumSPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + + replaceCompEqIdx = GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx), + + pressureIdx = Indices::pressureIdx, + switchIdx = Indices::switchIdx, + + wPhaseIdx = FluidSystem::wPhaseIdx, + nPhaseIdx = FluidSystem::nPhaseIdx, + + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx, + + conti0EqIdx = Indices::conti0EqIdx, + + wPhaseOnly = Indices::wPhaseOnly, + nPhaseOnly = Indices::nPhaseOnly, + bothPhases = Indices::bothPhases, + + plSg = TwoPNCFormulation::plSg, + pgSl = TwoPNCFormulation::pgSl, + formulation = GET_PROP_VALUE(TypeTag, Formulation) + }; + + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, SpatialParams) SpatialParams; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + +public: + /*! + * \brief Constructor. Sets the upwind weight. + */ + TwoPNCMinLocalResidual() + { + // 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 + this->massUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); + }; + + /*! + * \brief Evaluate the amount all conservation quantities + * (e.g. phase mass) within a sub-control volume. + * + * The result should be averaged over the volume (e.g. phase mass + * inside a sub control volume divided by the volume). + * In contrast to the 2pnc model, here, the storage of solid phases is included too. + * + * \param storage the mass of the component 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 + { + //call parenttype function + ParentType::computeStorage(storage, scvIdx, usePrevSol); + + const ElementVolumeVariables &elemVolVars = usePrevSol ? this->prevVolVars_() + : this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[scvIdx]; + + // Compute storage term of all solid (precipitated) phases (excluding the non-reactive matrix) + for (int phaseIdx = numPhases; phaseIdx < numPhases + numSPhases; ++phaseIdx) + { + int eqIdx = conti0EqIdx + numComponents-numPhases + phaseIdx; + storage[eqIdx] += volVars.precipitateVolumeFraction(phaseIdx)*volVars.molarDensity(phaseIdx); + } + + Valgrind::CheckDefined(storage); + } +}; +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/2pncmin/implicit/model.hh b/dumux/porousmediumflow/2pncmin/implicit/model.hh new file mode 100644 index 0000000000..9649493ab9 --- /dev/null +++ b/dumux/porousmediumflow/2pncmin/implicit/model.hh @@ -0,0 +1,551 @@ +// -*- 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 box scheme to the two-phase n-component flow model. +*/ + +#ifndef DUMUX_2PNCMIN_MODEL_HH +#define DUMUX_2PNCMIN_MODEL_HH + +#include "properties.hh" +#include "indices.hh" + +#include <dumux/material/constants.hh> +#include <dumux/porousmediumflow/2pnc/implicit/model.hh> +#include "localresidual.hh" +#include <dumux/porousmediumflow/implicit/velocityoutput.hh> + +namespace Dumux +{ +/*! + * \ingroup TwoPNCMinModel + * \brief Adaption of the fully implicit scheme to the + * two-phase n-component fully implicit model. + * + * This model implements two-phase n-component flow of two compressible and + * partially miscible fluids \f$\alpha \in \{ w, n \}\f$ composed of the n components + * \f$\kappa \in \{ w, a,\cdots \}\f$. The standard multiphase Darcy + * approach is used as the equation for the conservation of momentum: + * \f[ + v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} + \left(\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) + * \f] + * + * By inserting this into the equations for the conservation of the + * components, one gets one transport equation for each component + * \f{eqnarray} + && \phi \frac{\partial (\sum_\alpha \varrho_\alpha X_\alpha^\kappa S_\alpha )} + {\partial t} + - \sum_\alpha \text{div} \left\{ \varrho_\alpha X_\alpha^\kappa + \frac{k_{r\alpha}}{\mu_\alpha} \mbox{\bf K} + (\text{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g}) \right\} + \nonumber \\ \nonumber \\ + &-& \sum_\alpha \text{div} \left\{{\bf D_{\alpha, pm}^\kappa} \varrho_{\alpha} \text{grad}\, X^\kappa_{\alpha} \right\} + - \sum_\alpha q_\alpha^\kappa = 0 \qquad \kappa \in \{w, a,\cdots \} \, , + \alpha \in \{w, g\} + \f} + * + * All equations are discretized using a vertex-centered finite volume (box) + * or cell-centered finite volume scheme (this is not done for 2pnc approach yet, however possible) as + * spatial and the implicit Euler method as time discretization. + * + * By using constitutive relations for the capillary pressure \f$p_c = + * p_n - p_w\f$ and relative permeability \f$k_{r\alpha}\f$ and taking + * advantage of the fact that \f$S_w + S_n = 1\f$ and \f$X^\kappa_w + X^\kappa_n = 1\f$, the number of + * unknowns can be reduced to number of components. + * + * The used primary variables are, like in the two-phase model, either \f$p_w\f$ and \f$S_n\f$ + * or \f$p_n\f$ and \f$S_w\f$. The formulation which ought to be used can be + * specified by setting the <tt>Formulation</tt> property to either + * TwoPTwoCIndices::pWsN or TwoPTwoCIndices::pNsW. By + * default, the model uses \f$p_w\f$ and \f$S_n\f$. + * + * Moreover, the second primary variable depends on the phase state, since a + * primary variable switch is included. The phase state is stored for all nodes + * of the system. The model is uses mole fractions. + *Following cases can be distinguished: + * <ul> + * <li> Both phases are present: The saturation is used (either \f$S_n\f$ or \f$S_w\f$, dependent on the chosen <tt>Formulation</tt>), + * as long as \f$ 0 < S_\alpha < 1\f$</li>. + * <li> Only wetting phase is present: The mass fraction of, e.g., air in the wetting phase \f$X^a_w\f$ is used, + * as long as the maximum mass fraction is not exceeded (\f$X^a_w<X^a_{w,max}\f$)</li> + * <li> Only non-wetting phase is present: The mass fraction of, e.g., water in the non-wetting phase, \f$X^w_n\f$, is used, + * as long as the maximum mass fraction is not exceeded (\f$X^w_n<X^w_{n,max}\f$)</li> + * </ul> + */ + +template<class TypeTag> +class TwoPNCMinModel: public TwoPNCModel<TypeTag> +{ + typedef TwoPNCMinModel<TypeTag> ThisType; + typedef TwoPNCModel<TypeTag> ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; + typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef Dumux::Constants<Scalar> Constant; + + enum { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld, + + numEq = GET_PROP_VALUE(TypeTag, NumEq), + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numSPhases = GET_PROP_VALUE(TypeTag, NumSPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + numSecComponents = GET_PROP_VALUE(TypeTag, NumSecComponents), + numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents), + + pressureIdx = Indices::pressureIdx, + switchIdx = Indices::switchIdx, + + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx, + + wPhaseOnly = Indices::wPhaseOnly, + nPhaseOnly = Indices::nPhaseOnly, + bothPhases = Indices::bothPhases, + + plSg = TwoPNCFormulation::plSg, + pgSl = TwoPNCFormulation::pgSl, + formulation = GET_PROP_VALUE(TypeTag, Formulation) + }; + + typedef typename GridView::template Codim<dim>::Entity Vertex; + typedef typename GridView::template Codim<0>::Entity Element; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef typename GridView::ctype CoordScalar; + typedef Dune::FieldMatrix<CoordScalar, dimWorld, dimWorld> Tensor; + typedef Dune::FieldVector<Scalar, numPhases> PhasesVector; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + +public: + + /*! + * \brief Append all quantities of interest which can be derived + * from the solution of the current time step to the VTK + * writer. + * + * \param sol The solution vector + * \param writer The writer for multi-file VTK datasets + */ + template<class MultiWriter> + //additional output of the permeability and the precipitate volume fractions + void addOutputVtkFields(const SolutionVector &sol, + MultiWriter &writer) + { + typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<double, dim> > VectorField; + + // get the number of degrees of freedom + unsigned numDofs = this->numDofs(); + + // create the required scalar fields + ScalarField *Sg = writer.allocateManagedBuffer (numDofs); + ScalarField *Sl = writer.allocateManagedBuffer (numDofs); + ScalarField *pg = writer.allocateManagedBuffer (numDofs); + ScalarField *pl = writer.allocateManagedBuffer (numDofs); + ScalarField *pc = writer.allocateManagedBuffer (numDofs); + ScalarField *rhoL = writer.allocateManagedBuffer (numDofs); + ScalarField *rhoG = writer.allocateManagedBuffer (numDofs); + ScalarField *mobL = writer.allocateManagedBuffer (numDofs); + ScalarField *mobG = writer.allocateManagedBuffer (numDofs); + ScalarField *phasePresence = writer.allocateManagedBuffer (numDofs); + ScalarField *temperature = writer.allocateManagedBuffer (numDofs); + ScalarField *poro = writer.allocateManagedBuffer (numDofs); + ScalarField *boxVolume = writer.allocateManagedBuffer (numDofs); + ScalarField *cellNum = writer.allocateManagedBuffer (numDofs); + ScalarField *permeabilityFactor = writer.allocateManagedBuffer (numDofs); + ScalarField *precipitateVolumeFraction[numSPhases] ; + + for (int i = 0; i < numSPhases; ++i) + { + precipitateVolumeFraction[i]= writer.allocateManagedBuffer (numDofs); + } + + ScalarField *massFraction[numPhases][numComponents]; + for (int i = 0; i < numPhases; ++i) + for (int j = 0; j < numComponents; ++j) + massFraction[i][j] = writer.allocateManagedBuffer(numDofs); + + ScalarField *molarity[numComponents]; + for (int j = 0; j < numComponents ; ++j) + molarity[j] = writer.allocateManagedBuffer(numDofs); + + ScalarField *Perm[dim]; + for (int j = 0; j < dim; ++j) //Permeability only in main directions xx and yy + Perm[j] = writer.allocateManagedBuffer(numDofs); + + *boxVolume = 0; + + VectorField *velocityN = writer.template allocateManagedBuffer<double, dim>(numDofs); + VectorField *velocityW = writer.template allocateManagedBuffer<double, dim>(numDofs); + ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + // initialize velocity fields + for (unsigned int i = 0; i < numDofs; ++i) + { + (*velocityN)[i] = Scalar(0); + (*velocityW)[i] = Scalar(0); + (*cellNum)[i] = Scalar(0.0); + } + } + + unsigned numElements = this->gridView_().size(0); + ScalarField *rank = + writer.allocateManagedBuffer (numElements); + + FVElementGeometry fvGeometry; + VolumeVariables volVars; + ElementVolumeVariables elemVolVars; + + for (const auto& element : Dune::elements(this->gridView_())) + { + int idx = this->problem_().elementMapper().index(element); + (*rank)[idx] = this->gridView_().comm().rank(); + fvGeometry.update(this->gridView_(), element); + + elemVolVars.update(this->problem_(), + element, + fvGeometry, + false /* oldSol? */); + + int numVerts = element.subEntities(dim); + + for (int i = 0; i < numVerts; ++i) + { + int globalIdx = this->vertexMapper().subIndex(element, i, dim); + volVars.update(sol[globalIdx], + this->problem_(), + element, + fvGeometry, + i, + false); + + (*Sg)[globalIdx] = volVars.saturation(nPhaseIdx); + (*Sl)[globalIdx] = volVars.saturation(wPhaseIdx); + (*pg)[globalIdx] = volVars.pressure(nPhaseIdx); + (*pl)[globalIdx] = volVars.pressure(wPhaseIdx); + (*pc)[globalIdx] = volVars.capillaryPressure(); + (*rhoL)[globalIdx] = volVars.density(wPhaseIdx); + (*rhoG)[globalIdx] = volVars.density(nPhaseIdx); + (*mobL)[globalIdx] = volVars.mobility(wPhaseIdx); + (*mobG)[globalIdx] = volVars.mobility(nPhaseIdx); + (*boxVolume)[globalIdx] += fvGeometry.subContVol[i].volume; + (*poro)[globalIdx] = volVars.porosity(); + + for (int sPhaseIdx = 0; sPhaseIdx < numSPhases; ++sPhaseIdx) + { + (*precipitateVolumeFraction[sPhaseIdx])[globalIdx] = volVars.precipitateVolumeFraction(sPhaseIdx + numPhases); + } + (*temperature)[globalIdx] = volVars.temperature(); + (*permeabilityFactor)[globalIdx] = volVars.permeabilityFactor(); + (*phasePresence)[globalIdx] = this->staticDat_[globalIdx].phasePresence; + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + (*massFraction[phaseIdx][compIdx])[globalIdx]= volVars.massFraction(phaseIdx,compIdx); + + Valgrind::CheckDefined((*massFraction[phaseIdx][compIdx])[globalIdx]); + + } + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + (*molarity[compIdx])[globalIdx] = (volVars.molarity(wPhaseIdx, compIdx)); + + Tensor K = this->perm_(this->problem_().spatialParams().intrinsicPermeability(element, fvGeometry, i)); + + for (int j = 0; j<dim; ++j) + (*Perm[j])[globalIdx] = K[j][j] * volVars.permeabilityFactor(); + }; + + // velocity output + if(velocityOutput.enableOutput()){ + velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); + velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); + } + } // loop over element + + writer.attachVertexData(*Sg, "Sg"); + writer.attachVertexData(*Sl, "Sl"); + writer.attachVertexData(*pg, "pg"); + writer.attachVertexData(*pl, "pl"); + writer.attachVertexData(*pc, "pc"); + writer.attachVertexData(*rhoL, "rhoL"); + writer.attachVertexData(*rhoG, "rhoG"); + writer.attachVertexData(*mobL, "mobL"); + writer.attachVertexData(*mobG, "mobG"); + writer.attachVertexData(*poro, "porosity"); + writer.attachVertexData(*permeabilityFactor, "permeabilityFactor"); + writer.attachVertexData(*temperature, "temperature"); + writer.attachVertexData(*phasePresence, "phase presence"); + writer.attachVertexData(*boxVolume, "boxVolume"); + + + for (int i = 0; i < numSPhases; ++i) + { + std::ostringstream oss; + oss << "precipitateVolumeFraction_" + << FluidSystem::phaseName(numPhases + i); + writer.attachDofData(*precipitateVolumeFraction[i], oss.str().c_str(), isBox); + } + + writer.attachVertexData(*Perm[0], "Kxx"); + if (dim >= 2) + writer.attachVertexData(*Perm[1], "Kyy"); + if (dim == 3) + writer.attachVertexData(*Perm[2], "Kzz"); + + for (int i = 0; i < numPhases; ++i) + { + for (int j = 0; j < numComponents; ++j) + { + std::ostringstream oss; + oss << "X^" + << FluidSystem::phaseName(i) + << "_" + << FluidSystem::componentName(j); + writer.attachVertexData(*massFraction[i][j], oss.str().c_str()); + } + } + + for (int j = 0; j < numComponents; ++j) + { + std::ostringstream oss; + oss << "m^w_" + << FluidSystem::componentName(j); + writer.attachVertexData(*molarity[j], oss.str().c_str()); + } + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + writer.attachDofData(*velocityW, "velocityW", isBox, dim); + writer.attachDofData(*velocityN, "velocityN", isBox, dim); + } + + writer.attachCellData(*rank, "process rank"); + } + + /*! + * \brief Update the static data of all vertices in the grid. + * + * \param curGlobalSol The current global solution + * \param oldGlobalSol The previous global solution + */ + void updateStaticData(SolutionVector &curGlobalSol, + const SolutionVector &oldGlobalSol) + { + bool wasSwitched = false; + + for (unsigned i = 0; i < this->staticDat_.size(); ++i) + this->staticDat_[i].visited = false; + + FVElementGeometry fvGeometry; + static VolumeVariables volVars; + for (const auto& element : Dune::elements(this->gridView_())) + { + fvGeometry.update(this->gridView_(), element); + for (int i = 0; i < fvGeometry.numScv; ++i) + { + int globalIdx = this->vertexMapper().subIndex(element, i, dim); + + if (this->staticDat_[globalIdx].visited) + continue; + + this->staticDat_[globalIdx].visited = true; + volVars.update(curGlobalSol[globalIdx], + this->problem_(), + element, + fvGeometry, + i, + false); + const GlobalPosition &global = element.geometry().corner(i); + if (primaryVarSwitch_(curGlobalSol, + volVars, + globalIdx, + global)) + { wasSwitched = true; + } + } + } + + // make sure that if there was a variable switch in an + // other partition we will also set the switch flag + // for our partition. + if (this->gridView_().comm().size() > 1) + wasSwitched = this->gridView_().comm().max(wasSwitched); + + setSwitched_(wasSwitched); + } +protected: + + /*! + * \brief Set whether there was a primary variable switch after in + * the last timestep. + */ + void setSwitched_(bool yesno) + { + switchFlag_ = yesno; + } + + /*! + * \copydoc 2pnc::primaryVarSwitch_ + */ + bool primaryVarSwitch_(SolutionVector &globalSol, + const VolumeVariables &volVars, int globalIdx, + const GlobalPosition &globalPos) + { + // evaluate primary variable switch + bool wouldSwitch = false; + int phasePresence = this->staticDat_[globalIdx].phasePresence; + int newPhasePresence = phasePresence; + + //check if a primary variable switch is necessary + if (phasePresence == bothPhases) + { + Scalar Smin = 0.0; //saturation threshold + if (this->staticDat_[globalIdx].wasSwitched) + Smin = -0.01; + + //if saturation of liquid phase is smaller 0 switch + if (volVars.saturation(wPhaseIdx) <= Smin) + { + wouldSwitch = true; + //liquid phase has to disappear + std::cout << "Liquid Phase disappears at vertex " << globalIdx + << ", coordinated: " << globalPos << ", Sl: " + << volVars.saturation(wPhaseIdx) << std::endl; + newPhasePresence = nPhaseOnly; + + //switch not depending on formulation + //switch "Sl" to "xgH20" + globalSol[globalIdx][switchIdx] + = volVars.moleFraction(nPhaseIdx, wCompIdx /*H2O*/); + //Here unlike 2pnc model we do not switch all components to to mole fraction in gas phase + } + //if saturation of gas phase is smaller than 0 switch + else if (volVars.saturation(nPhaseIdx) <= Smin) + { + wouldSwitch = true; + //gas phase has to disappear + std::cout << "Gas Phase disappears at vertex " << globalIdx + << ", coordinated: " << globalPos << ", Sg: " + << volVars.saturation(nPhaseIdx) << std::endl; + newPhasePresence = wPhaseOnly; + + //switch "Sl" to "xlN2" + globalSol[globalIdx][switchIdx] + = volVars.moleFraction(wPhaseIdx, nCompIdx /*N2*/); + } + } + else if (phasePresence == nPhaseOnly) + { + Scalar sumxl = 0; + //Calculate sum of mole fractions (water and air) in the hypothetical liquid phase + //WARNING: Here numComponents is replaced by numMajorComponents as the solutes + //are only present in the liquid phase and cannot condense as the liquid (water). + for (int compIdx = 0; compIdx < numComponents; compIdx++) + { + sumxl += volVars.moleFraction(wPhaseIdx, compIdx); + } + Scalar xlmax = 1.0; + if (sumxl > xlmax) + wouldSwitch = true; + if (this->staticDat_[globalIdx].wasSwitched) + xlmax *=1.02; + + //if the sum of the mole fractions would be larger than + //1, wetting phase appears + if (sumxl/*sum of mole fractions*/ > xlmax/*1*/) + { + // liquid phase appears + std::cout << "Liquid Phase appears at vertex " << globalIdx + << ", coordinated: " << globalPos << ", sumxl: " + << sumxl << std::endl; + newPhasePresence = bothPhases; + if (formulation == pgSl) + globalSol[globalIdx][switchIdx] = 0.0; + else if (formulation == plSg) + globalSol[globalIdx][switchIdx] = 1.0; + //Here unlike 2pnc model we do not switch all components to to mole fraction in gas phase + } + } + else if (phasePresence == wPhaseOnly) + { + Scalar xgmax = 1; + Scalar sumxg = 0; + //Calculate sum of mole fractions in the hypothetical gas phase + for (int compIdx = 0; compIdx < numComponents; compIdx++) + { + sumxg += volVars.moleFraction(nPhaseIdx, compIdx); + } + if (sumxg > xgmax) + wouldSwitch = true; + if (this->staticDat_[globalIdx].wasSwitched) + xgmax *=1.02; + //liquid phase appears if sum is larger than one + if (sumxg > xgmax) + { + std::cout << "Gas Phase appears at vertex " << globalIdx + << ", coordinated: " << globalPos << ", sumxg: " + << sumxg << std::endl; + newPhasePresence = bothPhases; + //saturation of the liquid phase set to 0.9999 (if formulation pgSl and vice versa) + if (formulation == pgSl) + globalSol[globalIdx][switchIdx] = 0.999; + else if (formulation == plSg) + globalSol[globalIdx][switchIdx] = 0.001; + + } + } + this->staticDat_[globalIdx].phasePresence = newPhasePresence; + this->staticDat_[globalIdx].wasSwitched = wouldSwitch; + return phasePresence != newPhasePresence; + } + // parameters given in constructor + bool switchFlag_; +}; + +} + +#include "propertydefaults.hh" + +#endif diff --git a/dumux/porousmediumflow/2pncmin/implicit/properties.hh b/dumux/porousmediumflow/2pncmin/implicit/properties.hh new file mode 100644 index 0000000000..2171d0bc83 --- /dev/null +++ b/dumux/porousmediumflow/2pncmin/implicit/properties.hh @@ -0,0 +1,65 @@ +// -**- 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 TwoPNCMinModel + * + * \file + * + * \brief Defines the properties required for the two-phase n-component mineralization + * fully implicit model. + */ +#ifndef DUMUX_2PNCMIN_PROPERTIES_HH +#define DUMUX_2PNCMIN_PROPERTIES_HH + +#include <dumux/porousmediumflow/2pnc/implicit/properties.hh> + +namespace Dumux +{ + +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tag for the isothermal two phase n component mineralisation problems +NEW_TYPE_TAG(TwoPNCMin, INHERITS_FROM(TwoPNC)); +NEW_TYPE_TAG(BoxTwoPNCMin, INHERITS_FROM(BoxModel, TwoPNCMin)); +NEW_TYPE_TAG(CCTwoPNCMin, INHERITS_FROM(CCModel, TwoPNCMin)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +NEW_PROP_TAG(NumSPhases); //!< Number of solid phases in the system +NEW_PROP_TAG(NumFSPhases); //!< Number of fluid and solid phases in the system +NEW_PROP_TAG(NumSComponents); //!< Number of solid components in the system +NEW_PROP_TAG(NumPSComponents); //!< Number of fluid and solid components in the system +NEW_PROP_TAG(NumTraceComponents); //!< Number of trace fluid components which are not considered in the calculation of the phase density +NEW_PROP_TAG(NumSecComponents); //!< Number of secondary components which are not primary variables +NEW_PROP_TAG(TwoPNCMinIndices); //!< Enumerations for the 2pncMin models +NEW_PROP_TAG(useSalinity); //!< Determines if salinity is used +NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient + +} +} + +#endif diff --git a/dumux/porousmediumflow/2pncmin/implicit/propertydefaults.hh b/dumux/porousmediumflow/2pncmin/implicit/propertydefaults.hh new file mode 100644 index 0000000000..e3854eb01e --- /dev/null +++ b/dumux/porousmediumflow/2pncmin/implicit/propertydefaults.hh @@ -0,0 +1,143 @@ +// -**- 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 TwoPNCMinModel + * \file + * + * \brief Defines default values for most properties required by the + * two-phase n-component mineralization fully implicit model. + */ +#ifndef DUMUX_2PNCMIN_PROPERTY_DEFAULTS_HH +#define DUMUX_2PNCMIN_PROPERTY_DEFAULTS_HH + +#include "indices.hh" +#include "model.hh" +#include "indices.hh" +#include "fluxvariables.hh" +#include "volumevariables.hh" +#include "properties.hh" + +#include <dumux/porousmediumflow/2pnc/implicit/newtoncontroller.hh> +#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> +#include <dumux/material/spatialparams/implicitspatialparams.hh> + +namespace Dumux +{ + +namespace Properties { +////////////////////////////////////////////////////////////////// +// Property values +////////////////////////////////////////////////////////////////// + +/*! + * \brief Set the property for the number of secondary components. + * Secondary components are components calculated from + * primary components by equilibrium relations and + * do not have mass balance equation on their own. + * These components are important in the context of bio-mineralization applications. + * We just forward the number from the fluid system + * + */ +SET_PROP(TwoPNCMin, NumSecComponents) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numSecComponents; + +}; +/*! + * \brief Set the property for the number of solid phases, excluding the non-reactive matrix. + * + * We just forward the number from the fluid system + * + */ +SET_PROP(TwoPNCMin, NumSPhases) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numSPhases; +}; + +/*! + * \brief Set the property for the number of equations. + * For each component and each precipitated mineral/solid phase one equation has to + * be solved. + */ +SET_PROP(TwoPNCMin, NumEq) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluidSystem)) FluidSystem; + +public: + static const int value = FluidSystem::numComponents + FluidSystem::numSPhases; +}; + +/*! + * \brief The fluid state which is used by the volume variables to + * store the thermodynamic state. This should be chosen + * appropriately for the model ((non-)isothermal, equilibrium, ...). + * This can be done in the problem. + */ +SET_PROP(TwoPNCMin, 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; +}; + +//! Use the 2pncmin local residual operator +SET_TYPE_PROP(TwoPNCMin, + LocalResidual, + TwoPNCMinLocalResidual<TypeTag>); + +//! the Model property +SET_TYPE_PROP(TwoPNCMin, Model, TwoPNCMinModel<TypeTag>); + +//! the VolumeVariables property +SET_TYPE_PROP(TwoPNCMin, VolumeVariables, TwoPNCMinVolumeVariables<TypeTag>); + +//! the FluxVariables property +SET_TYPE_PROP(TwoPNCMin, FluxVariables, TwoPNCMinFluxVariables<TypeTag>); + +//! The indices required by the isothermal 2pNcMin model +SET_TYPE_PROP(TwoPNCMin, Indices, TwoPNCMinIndices <TypeTag, /*PVOffset=*/0>); + +//! disable useSalinity for the calculation of osmotic pressure by default +SET_BOOL_PROP(TwoPNCMin, useSalinity, false); + + +//! default value for the forchheimer coefficient +// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. +// Actually the Forchheimer coefficient is also a function of the dimensions of the +// porous medium. Taking it as a constant is only a first approximation +// (Nield, Bejan, Convection in porous media, 2006, p. 10) +SET_SCALAR_PROP(TwoPNCMin, SpatialParamsForchCoeff, 0.55); + +} + +} + +#endif diff --git a/dumux/porousmediumflow/2pncmin/implicit/volumevariables.hh b/dumux/porousmediumflow/2pncmin/implicit/volumevariables.hh new file mode 100644 index 0000000000..84850e8988 --- /dev/null +++ b/dumux/porousmediumflow/2pncmin/implicit/volumevariables.hh @@ -0,0 +1,549 @@ +// -**- 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 Contains the quantities which are constant within a + * finite volume in the two-phase, n-component mineralization model. + */ +#ifndef DUMUX_2PNCMin_VOLUME_VARIABLES_HH +#define DUMUX_2PNCMin_VOLUME_VARIABLES_HH + +#include <dumux/implicit/model.hh> +#include <dumux/material/fluidstates/compositionalfluidstate.hh> +#include <dumux/common/math.hh> +#include <vector> +#include <iostream> + +#include "properties.hh" +#include "indices.hh" +#include <dumux/material/constraintsolvers/computefromreferencephase2pncmin.hh> +#include <dumux/material/constraintsolvers/miscible2pnccomposition.hh> +#include <dumux/porousmediumflow/2pnc/implicit/volumevariables.hh> + +namespace Dumux +{ + +/*! + * \ingroup TwoPNCMinModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are are constant within a + * finite volume in the two-phase, n-component model. + */ +template <class TypeTag> +class TwoPNCMinVolumeVariables : public TwoPNCVolumeVariables<TypeTag> +{ + typedef TwoPNCVolumeVariables<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum + { + dim = GridView::dimension, + dimWorld=GridView::dimensionworld, + + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numSPhases = GET_PROP_VALUE(TypeTag, NumSPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + numMajorComponents = GET_PROP_VALUE(TypeTag, NumMajorComponents), + + // formulations + formulation = GET_PROP_VALUE(TypeTag, Formulation), + plSg = TwoPNCFormulation::plSg, + pgSl = TwoPNCFormulation::pgSl, + + // phase indices + wPhaseIdx = FluidSystem::wPhaseIdx, + nPhaseIdx = FluidSystem::nPhaseIdx, + + // component indices + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx, + + // phase presence enums + nPhaseOnly = Indices::nPhaseOnly, + wPhaseOnly = Indices::wPhaseOnly, + bothPhases = Indices::bothPhases, + + // primary variable indices + pressureIdx = Indices::pressureIdx, + switchIdx = Indices::switchIdx, + + useSalinity = GET_PROP_VALUE(TypeTag, useSalinity) + }; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef typename Grid::ctype CoordScalar; + typedef Dumux::Miscible2pNCComposition<Scalar, FluidSystem> Miscible2pNCComposition; + typedef Dumux::ComputeFromReferencePhase2pNCMin<Scalar, FluidSystem> ComputeFromReferencePhase2pNCMin; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; +public: + + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; + + /*! + * \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); + + completeFluidState(priVars, problem, element, fvGeometry, scvIdx, this->fluidState_, isOldSol); + + ///////////// + // calculate the remaining quantities + ///////////// + + // porosity evaluation + initialPorosity_ = problem.spatialParams().porosity(element, fvGeometry, scvIdx); + minimumPorosity_ = problem.spatialParams().porosityMin(element, fvGeometry, scvIdx); + + + sumPrecipitates_ = 0.0; + for(int sPhaseIdx = 0; sPhaseIdx < numSPhases; ++sPhaseIdx) + { + precipitateVolumeFraction_[sPhaseIdx] = priVars[numComponents + sPhaseIdx]; + sumPrecipitates_+= precipitateVolumeFraction_[sPhaseIdx]; + } + +// for(int sPhaseIdx = 0; sPhaseIdx < numSPhases; ++sPhaseIdx) +// { +// Chemistry chemistry; // the non static functions can not be called without abject +// saturationIdx_[sPhaseIdx] = chemistry.omega(sPhaseIdx); +// } +// TODO/FIXME: The salt crust porosity is not clearly defined. However form literature review it is +// found that the salt crust have porosity of approx. 10 %. Thus we restrict the decrease in porosity +// to this limit. Moreover in the Problem files the precipitation should also be made dependent on local +// porosity value, as the porous media media properties change related to salt precipitation will not be +// accounted otherwise. + +// this->porosity_ = initialPorosity_ - sumPrecipitates_; + + this->porosity_ = std::max(minimumPorosity_, std::max(0.0, initialPorosity_ - sumPrecipitates_)); + + salinity_= 0.0; + moleFractionSalinity_ = 0.0; + for (int compIdx = numMajorComponents; compIdx< numComponents; compIdx++) //sum of the mass fraction of the components + { + if(this->fluidState_.moleFraction(wPhaseIdx, compIdx)> 0) + { + salinity_+= this->fluidState_.massFraction(wPhaseIdx, compIdx); + moleFractionSalinity_ += this->fluidState_.moleFraction(wPhaseIdx, compIdx); + } + } + +// TODO/FIXME: Different relations for the porosoty-permeability changes are given here. We have to fins a way +// so that one can select the relation form the input file. + + // kozeny-Carman relation + permeabilityFactor_ = std::pow(((1-initialPorosity_)/(1-this->porosity_)),2) + * std::pow((this->porosity_/initialPorosity_),3); + + // Verma-Pruess relation +// permeabilityFactor_ = 100 * std::pow(((this->porosity_/initialPorosity_)-0.9),2); + + // Modified Fair-Hatch relation with final porosity set to 0.2 and E1=1 +// permeabilityFactor_ = std::pow((this->porosity_/initialPorosity_),3) +// * std::pow((std::pow((1 - initialPorosity_),2/3))+(std::pow((0.2 - initialPorosity_),2/3)),2) +// / std::pow((std::pow((1 -this->porosity_),2/3))+(std::pow((0.2 -this->porosity_),2/3)),2); + + //Timur relation with residual water saturation set to 0.001 +// permeabilityFactor_ = 0.136 * (std::pow(this->porosity_,4.4)) / (2000 * (std::pow(0.001,2))); + + //Timur relation1 with residual water saturation set to 0.001 +// permeabilityFactor_ = 0.136 * (std::pow(this->porosity_,4.4)) / (200000 * (std::pow(0.001,2))); + + + //Bern. relation + // permeabilityFactor_ = std::pow((this->porosity_/initialPorosity_),8); + + //Tixier relation with residual water saturation set to 0.001 + //permeabilityFactor_ = (std::pow((250 * (std::pow(this->porosity_,3)) / 0.001),2)) / initialPermeability_; + + //Coates relation with residual water saturation set to 0.001 + //permeabilityFactor_ = (std::pow((100 * (std::pow(this->porosity_,2)) * (1-0.001) / 0.001,2))) / initialPermeability_ ; + + + // energy related quantities not contained in the fluid state + //asImp_().updateEnergy_(priVars, problem,element, fvGeometry, scvIdx, isOldSol); + } + + /*! + * \copydoc ImplicitModel::completeFluidState + * \param isOldSol Specifies whether this is the previous solution or the current one + */ + static void completeFluidState(const PrimaryVariables& priVars, + const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + int scvIdx, + FluidState& fluidState, + bool isOldSol = false) + + { + Scalar t = Implementation::temperature_(priVars, problem, element,fvGeometry, scvIdx); + fluidState.setTemperature(t); + + int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); + int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); + + ///////////// + // set the saturations + ///////////// + + Scalar Sg; + if (phasePresence == nPhaseOnly) + Sg = 1.0; + else if (phasePresence == wPhaseOnly) { + Sg = 0.0; + } + else if (phasePresence == bothPhases) { + if (formulation == plSg) + Sg = priVars[switchIdx]; + else if (formulation == pgSl) + Sg = 1.0 - priVars[switchIdx]; + else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); + } + else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); + fluidState.setSaturation(nPhaseIdx, Sg); + fluidState.setSaturation(wPhaseIdx, 1.0 - Sg); + + ///////////// + // set the pressures of the fluid phases + ///////////// + + // calculate capillary pressure + const MaterialLawParams &materialParams = problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); + Scalar pc = MaterialLaw::pc(materialParams, 1 - Sg); + + // extract the pressures + if (formulation == plSg) { + fluidState.setPressure(wPhaseIdx, priVars[pressureIdx]); + fluidState.setPressure(nPhaseIdx, priVars[pressureIdx] + pc); + } + else if (formulation == pgSl) { + fluidState.setPressure(nPhaseIdx, priVars[pressureIdx]); + fluidState.setPressure(wPhaseIdx, priVars[pressureIdx] - pc); + } + else DUNE_THROW(Dune::InvalidStateException, "Formulation: " << formulation << " is invalid."); + + ///////////// + // calculate the phase compositions + ///////////// + + typename FluidSystem::ParameterCache paramCache; + + // now comes the tricky part: calculate phase composition + if (phasePresence == bothPhases) { + // both phases are present, phase composition results from + // the gas <-> liquid equilibrium. This is + // the job of the "MiscibleMultiPhaseComposition" + // constraint solver + + // set the known mole fractions in the fluidState so that they + // can be used by the Miscible2pNcComposition constraint solver + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + { + fluidState.setMoleFraction(wPhaseIdx, compIdx, priVars[compIdx]); + } + + Miscible2pNCComposition::solve(fluidState, + paramCache, + wPhaseIdx, //known phaseIdx + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + else if (phasePresence == nPhaseOnly){ + + Dune::FieldVector<Scalar, numComponents> moleFrac; + Dune::FieldVector<Scalar, numComponents> fugCoeffL; + Dune::FieldVector<Scalar, numComponents> fugCoeffG; + + for (int compIdx=0; compIdx<numComponents; ++compIdx) + { + fugCoeffL[compIdx] = FluidSystem::fugacityCoefficient(fluidState, + paramCache, + wPhaseIdx, + compIdx); + fugCoeffG[compIdx] = FluidSystem::fugacityCoefficient(fluidState, + paramCache, + nPhaseIdx, + compIdx); + } + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + moleFrac[compIdx] = (priVars[compIdx]*fugCoeffL[compIdx]*fluidState.pressure(wPhaseIdx)) + /(fugCoeffG[compIdx]*fluidState.pressure(nPhaseIdx)); + + moleFrac[wCompIdx] = priVars[switchIdx]; + Scalar sumMoleFracNotGas = 0; + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + { + sumMoleFracNotGas+=moleFrac[compIdx]; + } + sumMoleFracNotGas += moleFrac[wCompIdx]; + moleFrac[nCompIdx] = 1 - sumMoleFracNotGas; + +// typedef Dune::FieldMatrix<Scalar, numComponents, numComponents> Matrix; +// typedef Dune::FieldVector<Scalar, numComponents> Vector; + + + // Set fluid state mole fractions + for (int compIdx=0; compIdx<numComponents; ++compIdx) + { + fluidState.setMoleFraction(nPhaseIdx, compIdx, moleFrac[compIdx]); + } + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase2pNc" constraint solver + ComputeFromReferencePhase2pNCMin::solve(fluidState, + paramCache, + nPhaseIdx, + nPhaseOnly, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + + } + else if (phasePresence == wPhaseOnly){ + + // only the liquid phase is present, i.e. liquid phase + // composition is stored explicitly. + // extract _mass_ fractions in the gas phase + Dune::FieldVector<Scalar, numComponents> moleFrac; + + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + { + moleFrac[compIdx] = priVars[compIdx]; + } + moleFrac[nCompIdx] = priVars[switchIdx]; + Scalar sumMoleFracNotWater = 0; + for (int compIdx=numMajorComponents; compIdx<numComponents; ++compIdx) + { + sumMoleFracNotWater+=moleFrac[compIdx]; + } + sumMoleFracNotWater += moleFrac[nCompIdx]; + moleFrac[wCompIdx] = 1 -sumMoleFracNotWater; + +// convert mass to mole fractions and set the fluid state + for (int compIdx=0; compIdx<numComponents; ++compIdx) + { + fluidState.setMoleFraction(wPhaseIdx, compIdx, moleFrac[compIdx]); + } + +// calculate the composition of the remaining phases (as +// well as the densities of all phases). this is the job +// of the "ComputeFromReferencePhase2pNc" constraint solver + ComputeFromReferencePhase2pNCMin::solve(fluidState, + paramCache, + wPhaseIdx, + wPhaseOnly, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + paramCache.updateAll(fluidState); + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + Scalar h = Implementation::enthalpy_(fluidState, paramCache, phaseIdx); + fluidState.setEnthalpy(phaseIdx, h); + } + } + /*! + * \brief Returns the volume fraction of the precipitate (solid phase) + * for the given phaseIdx + * + * \param phaseIdx the index of the solid phase + */ + Scalar precipitateVolumeFraction(int phaseIdx) const + { return precipitateVolumeFraction_[phaseIdx - numPhases]; } + + /*! + * \brief Returns the inital porosity of the + * pure, precipitate-free porous medium + */ + Scalar initialPorosity() const + { return initialPorosity_;} + + /*! + * \brief Returns the inital permeability of the + * pure, precipitate-free porous medium + */ + Scalar initialPermeability() const + { return initialPermeability_;} + + /*! + * \brief Returns the factor for the reduction of the initial permeability + * due precipitates in the porous medium + */ + Scalar permeabilityFactor() const + { return permeabilityFactor_; } + +// /*! +// * \brief Returns the mole fraction of a component in the phase +// * +// * \param phaseIdx the index of the fluid phase +// * \param compIdx the index of the component +// */ +// Scalar moleFraction(int phaseIdx, int compIdx) const +// { +// return this->fluidState_.moleFraction(phaseIdx, compIdx); +// } + + /*! + * \brief Returns the mole fraction of the salinity in the liquid phase + */ + Scalar moleFracSalinity() const + { + return moleFractionSalinity_; + } + + /*! + * \brief Returns the salinity (mass fraction) in the liquid phase + */ + Scalar salinity() const + { + return salinity_; + } + + /*! + * \brief Returns the density of the phase for all fluid and solid phases + * + * \param phaseIdx the index of the fluid phase + */ + Scalar density(int phaseIdx) const + { + if (phaseIdx < numPhases) + return this->fluidState_.density(phaseIdx); + else if (phaseIdx >= numPhases) + return FluidSystem::precipitateDensity(phaseIdx); + else + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + /*! + * \brief Returns the mass density of a given phase within the + * control volume. + * + * \param phaseIdx The phase index + */ + Scalar molarDensity(int phaseIdx) const + { + if (phaseIdx < numPhases) + return this->fluidState_.molarDensity(phaseIdx); + else if (phaseIdx >= numPhases) + return FluidSystem::precipitateMolarDensity(phaseIdx); + else + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + /*! + * \brief Returns the molality of a component in the phase + * + * \param phaseIdx the index of the fluid phase + * \param compIdx the index of the component + * molality=\frac{n_{component}}{m_{solvent}} + * =\frac{n_{component}}{n_{solvent}*M_{solvent}} + * compIdx of the main component (solvent) in the + * phase is equal to the phaseIdx + */ + Scalar molality(int phaseIdx, int compIdx) const // [moles/Kg] + { return this->fluidState_.moleFraction(phaseIdx, compIdx) + /(fluidState_.moleFraction(phaseIdx, phaseIdx) + * FluidSystem::molarMass(phaseIdx));} + +protected: + friend class TwoPNCVolumeVariables<TypeTag>; + static Scalar temperature_(const PrimaryVariables &priVars, + const Problem& problem, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx) + { + return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); + } + + template<class ParameterCache> + static Scalar enthalpy_(const FluidState& fluidState, + const ParameterCache& paramCache, + int phaseIdx) + { + return 0; + } + + /*! + * \brief Update all quantities for a given control volume. + * + * \param priVars The solution primary variables + * \param problem The problem + * \param element The element + * \param fvGeometry Evaluate function with solution of current or previous time step + * \param scvIdx The local index of the SCV (sub-control volume) + * \param isOldSol Evaluate function with solution of current or previous time step + */ + void updateEnergy_(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx, + bool isOldSol) + { }; + + Scalar precipitateVolumeFraction_[numSPhases]; +// Scalar saturationIdx_[numSPhases]; + Scalar permeabilityFactor_; + Scalar initialPorosity_; + Scalar initialPermeability_; + Scalar minimumPorosity_; + Scalar sumPrecipitates_; + Scalar salinity_; + Scalar moleFractionSalinity_; + FluidState fluidState_; + +private: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/fluxvariables.hh b/dumux/porousmediumflow/3p3c/implicit/fluxvariables.hh new file mode 100644 index 0000000000..a579e5090d --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/fluxvariables.hh @@ -0,0 +1,386 @@ +// -*- 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 + * all fluxes of components over a face of a finite volume for + * the three-phase three-component model. + */ +#ifndef DUMUX_3P3C_FLUX_VARIABLES_HH +#define DUMUX_3P3C_FLUX_VARIABLES_HH + +#include <dumux/common/math.hh> +#include <dumux/common/spline.hh> + +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup ThreePThreeCModel + * \ingroup ImplicitFluxVariables + * \brief This template class contains the data which is required to + * calculate all fluxes of components over a face of a finite + * volume for the three-phase three-component model. + * + * This means pressure and concentration gradients, phase densities at + * the integration point, etc. + */ +template <class TypeTag> +class ThreePThreeCFluxVariables : public GET_PROP_TYPE(TypeTag, BaseFluxVariables) +{ + typedef typename GET_PROP_TYPE(TypeTag, BaseFluxVariables) BaseFluxVariables; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel) EffectiveDiffusivityModel; + + enum { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents) + }; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + gPhaseIdx = Indices::gPhaseIdx, + + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx, + gCompIdx = Indices::gCompIdx + }; + +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 Evaluate flux at inner sub-control-volume face or on a boundary face + */ + ThreePThreeCFluxVariables(const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int fIdx, + const ElementVolumeVariables &elemVolVars, + const bool onBoundary = false) + : BaseFluxVariables(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary) + { + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + density_[phaseIdx] = Scalar(0); + molarDensity_[phaseIdx] = Scalar(0); + massFractionCompWGrad_[phaseIdx] = Scalar(0); + massFractionCompNGrad_[phaseIdx] = Scalar(0); + massFractionCompGGrad_[phaseIdx] = Scalar(0); + moleFractionCompWGrad_[phaseIdx] = Scalar(0); + moleFractionCompNGrad_[phaseIdx] = Scalar(0); + moleFractionCompGGrad_[phaseIdx] = Scalar(0); + } + + calculateGradients_(problem, element, elemVolVars); + calculatePorousDiffCoeff_(problem, element, elemVolVars); + }; + +private: + void calculateGradients_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + // calculate gradients + GlobalPosition tmp(0.0); + for (unsigned int idx = 0; + idx < this->face().numFap; + idx++) // loop over adjacent vertices + { + // FE gradient at vertex idx + const GlobalPosition &feGrad = this->face().grad[idx]; + + // index for the element volume variables + int volVarsIdx = this->face().fapIndices[idx]; + + // the concentration gradient of the components + // component in the phases + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(wPhaseIdx, wCompIdx); + massFractionCompWGrad_[wPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(nPhaseIdx, wCompIdx); + massFractionCompWGrad_[nPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(gPhaseIdx, wCompIdx); + massFractionCompWGrad_[gPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(wPhaseIdx, nCompIdx); + massFractionCompNGrad_[wPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(nPhaseIdx, nCompIdx); + massFractionCompNGrad_[nPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(gPhaseIdx, nCompIdx); + massFractionCompNGrad_[gPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(wPhaseIdx, gCompIdx); + massFractionCompGGrad_[wPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(nPhaseIdx, gCompIdx); + massFractionCompGGrad_[nPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].massFraction(gPhaseIdx, gCompIdx); + massFractionCompGGrad_[gPhaseIdx] += tmp; + + // the molar concentration gradients of the components + // in the phases + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, wCompIdx); + moleFractionCompWGrad_[wPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, wCompIdx); + moleFractionCompWGrad_[nPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(gPhaseIdx, wCompIdx); + moleFractionCompWGrad_[gPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, nCompIdx); + moleFractionCompNGrad_[wPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, nCompIdx); + moleFractionCompNGrad_[nPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(gPhaseIdx, nCompIdx); + moleFractionCompNGrad_[gPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(wPhaseIdx, gCompIdx); + moleFractionCompGGrad_[wPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(nPhaseIdx, gCompIdx); + moleFractionCompGGrad_[nPhaseIdx] += tmp; + + tmp = feGrad; + tmp *= elemVolVars[volVarsIdx].moleFraction(gPhaseIdx, gCompIdx); + moleFractionCompGGrad_[gPhaseIdx] += tmp; + } + } + + Scalar rhoFactor_(int phaseIdx, int scvIdx, const ElementVolumeVariables &elemVolVars) + { + static const Scalar eps = 1e-2; + const Scalar sat = elemVolVars[scvIdx].density(phaseIdx); + if (sat > eps) + return 0.5; + if (sat <= 0) + return 0; + + static const Dumux::Spline<Scalar> sp(0, eps, // x0, x1 + 0, 0.5, // y0, y1 + 0, 0); // m0, m1 + return sp.eval(sat); + } + + void calculatePorousDiffCoeff_(const Problem &problem, + const Element &element, + const ElementVolumeVariables &elemVolVars) + { + + const VolumeVariables &volVarsI = elemVolVars[this->face().i]; + const VolumeVariables &volVarsJ = elemVolVars[this->face().j]; + + Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficientMatrix_i = volVarsI.diffusionCoefficient(); + Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficientMatrix_j = volVarsJ.diffusionCoefficient(); + + // the effective diffusion coefficients at vertex i and j + Scalar diffCoeffI; + Scalar diffCoeffJ; + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // make sure to calculate only diffusion coefficents + // for phases which exist in both finite volumes + /* \todo take care: This should be discussed once again + * as long as a meaningful value can be found for the required mole fraction + * diffusion should work even without this one here */ + if (volVarsI.saturation(phaseIdx) <= 0 || + volVarsJ.saturation(phaseIdx) <= 0) + { + porousDiffCoeff_[phaseIdx][wCompIdx] = 0.0; + porousDiffCoeff_[phaseIdx][nCompIdx] = 0.0; + porousDiffCoeff_[phaseIdx][gCompIdx] = 0.0; + continue; + } + + // Diffusion coefficient in the porous medium + diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), + volVarsI.saturation(phaseIdx), + diffusionCoefficientMatrix_i[phaseIdx][wCompIdx]); + diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), + volVarsJ.saturation(phaseIdx), + diffusionCoefficientMatrix_j[phaseIdx][wCompIdx]); + + // -> harmonic mean + porousDiffCoeff_[phaseIdx][wCompIdx] = harmonicMean(diffCoeffI, diffCoeffJ); + + // Diffusion coefficient in the porous medium + diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), + volVarsI.saturation(phaseIdx), + diffusionCoefficientMatrix_i[phaseIdx][nCompIdx]); + diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), + volVarsJ.saturation(phaseIdx), + diffusionCoefficientMatrix_j[phaseIdx][nCompIdx]); + + // -> harmonic mean + porousDiffCoeff_[phaseIdx][nCompIdx] = harmonicMean(diffCoeffI, diffCoeffJ); + + // Diffusion coefficient in the porous medium + diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(), + volVarsI.saturation(phaseIdx), + diffusionCoefficientMatrix_i[phaseIdx][gCompIdx]); + diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(), + volVarsJ.saturation(phaseIdx), + diffusionCoefficientMatrix_j[phaseIdx][gCompIdx]); + + // -> harmonic mean + porousDiffCoeff_[phaseIdx][gCompIdx] = harmonicMean(diffCoeffI, diffCoeffJ); + } + } + +public: + /*! + * \brief The diffusivity matrix + * + * \tparam Scalar Field type + * \tparam numPhases The number of phases of the problem + * \tparam numComponents The number of components of the problem + */ + Dune::FieldMatrix<Scalar, numPhases, numComponents> porousDiffCoeff() const + { return porousDiffCoeff_; }; + + /*! + * \brief Return density \f$\mathrm{[kg/m^3]}\f$ of a phase. + * + * \param phaseIdx The phase index + */ + Scalar density(int phaseIdx) const + { return density_[phaseIdx]; } + + /*! + * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ of a phase. + * + * \param phaseIdx The phase index + */ + Scalar molarDensity(int phaseIdx) const + { return molarDensity_[phaseIdx]; } + + /*! + * \brief The mass fraction gradient of the water in a phase. + * + * \param phaseIdx The phase index + */ + const GlobalPosition &massFractionCompWGrad(int phaseIdx) const + {return massFractionCompWGrad_[phaseIdx];} + + /*! + * \brief The mass fraction gradient of the contaminant in a phase. + * + * \param phaseIdx The phase index + */ + const GlobalPosition &massFractionCompNGrad(int phaseIdx) const + { return massFractionCompNGrad_[phaseIdx]; }; + + /*! + * \brief The mass fraction gradient of gas in a phase. + * + * \param phaseIdx The phase index + */ + const GlobalPosition &massFractionCompGGrad(int phaseIdx) const + { return massFractionCompGGrad_[phaseIdx]; }; + + /*! + * \brief The mole fraction gradient of the water in a phase. + * + * \param phaseIdx The phase index + */ + const GlobalPosition &moleFractionCompWGrad(int phaseIdx) const + { return moleFractionCompWGrad_[phaseIdx]; }; + + /*! + * \brief The mole fraction gradient of the contaminant in a phase. + * + * \param phaseIdx The phase index + */ + const GlobalPosition &moleFractionCompNGrad(int phaseIdx) const + { return moleFractionCompNGrad_[phaseIdx]; }; + + /*! + * \brief The mole fraction gradient of gas in a phase. + * + * \param phaseIdx The phase index + */ + const GlobalPosition &moleFractionCompGGrad(int phaseIdx) const + { return moleFractionCompGGrad_[phaseIdx]; }; + +protected: + // gradients + GlobalPosition massFractionCompWGrad_[numPhases]; + GlobalPosition massFractionCompNGrad_[numPhases]; + GlobalPosition massFractionCompGGrad_[numPhases]; + GlobalPosition moleFractionCompWGrad_[numPhases]; + GlobalPosition moleFractionCompNGrad_[numPhases]; + GlobalPosition moleFractionCompGGrad_[numPhases]; + + // density of each face at the integration point + Scalar density_[numPhases], molarDensity_[numPhases]; + + // the diffusivity matrix for the porous medium + Dune::FieldMatrix<Scalar, numPhases, numComponents> porousDiffCoeff_; +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/indices.hh b/dumux/porousmediumflow/3p3c/implicit/indices.hh new file mode 100644 index 0000000000..cd832f5ec6 --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/indices.hh @@ -0,0 +1,90 @@ +// -*- 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 indices required for the three-phase three-component + * fully implicit model. + */ +#ifndef DUMUX_3P3C_INDICES_HH +#define DUMUX_3P3C_INDICES_HH + +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup ThreePThreeCModel + * \ingroup ImplicitIndices + * \brief The indices for the isothermal three-phase three-component model. + * + * \tparam formulation The formulation, only pgSwSn is available. + * \tparam PVOffset The first index in a primary variable vector. + */ +template <class TypeTag, int PVOffset = 0> +class ThreePThreeCIndices +{ + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + +public: + // Phase indices + static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< index of the wetting liquid phase + static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< index of the nonwetting liquid phase + static const int gPhaseIdx = FluidSystem::gPhaseIdx; //!< index of the gas phase + + // Component indices to indicate the main component + // of the corresponding phase at atmospheric pressure 1 bar + // and room temperature 20°C: + static const int wCompIdx = FluidSystem::wCompIdx; + static const int nCompIdx = FluidSystem::nCompIdx; + static const int gCompIdx = FluidSystem::gCompIdx; + + // present phases (-> 'pseudo' primary variable) + static const int threePhases = 1; //!< All three phases are present + static const int wPhaseOnly = 2; //!< Only the water phase is present + static const int gnPhaseOnly = 3; //!< Only gas and NAPL phases are present + static const int wnPhaseOnly = 4; //!< Only water and NAPL phases are present + static const int gPhaseOnly = 5; //!< Only gas phase is present + static const int wgPhaseOnly = 6; //!< Only water and gas phases are present + + // Primary variable indices + static const int pressureIdx = PVOffset + 0; //!< Index for gas phase pressure in a solution vector + static const int switch1Idx = PVOffset + 1; //!< Index 1 of saturation or mole fraction + static const int switch2Idx = PVOffset + 2; //!< Index 2 of saturation or mole fraction + + //! Index for gas phase pressure in a solution vector + static const int pgIdx = pressureIdx; + //! Index of either the saturation of the wetting phase or the mole fraction secondary component if a phase is not present + static const int sOrX1Idx = switch1Idx; + //! Index of either the saturation of the nonwetting phase or the mole fraction secondary component if a phase is not present + static const int sOrX2Idx = switch2Idx; + + // equation indices + static const int conti0EqIdx = PVOffset + wCompIdx; //!< Index of the mass conservation equation for the water component + static const int conti1EqIdx = conti0EqIdx + nCompIdx; //!< Index of the mass conservation equation for the contaminant component + static const int conti2EqIdx = conti0EqIdx + gCompIdx; //!< Index of the mass conservation equation for the gas component + + static const int contiWEqIdx = conti0EqIdx + wCompIdx; //!< index of the mass conservation equation for the water component + static const int contiNEqIdx = conti0EqIdx + nCompIdx; //!< index of the mass conservation equation for the contaminant component + static const int contiGEqIdx = conti0EqIdx + gCompIdx; //!< index of the mass conservation equation for the air component +}; + +} + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/localresidual.hh b/dumux/porousmediumflow/3p3c/implicit/localresidual.hh new file mode 100644 index 0000000000..79014d6c22 --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/localresidual.hh @@ -0,0 +1,238 @@ +// -*- 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 Jacobian matrix for problems + * using the three-phase three-component fully implicit model. + */ +#ifndef DUMUX_3P3C_LOCAL_RESIDUAL_HH +#define DUMUX_3P3C_LOCAL_RESIDUAL_HH + +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup ThreePThreeCModel + * \ingroup ImplicitLocalResidual + * \brief Element-wise calculation of the Jacobian matrix for problems + * using the three-phase three-component fully implicit model. + * + * This class is used to fill the gaps in BoxLocalResidual for the 3P3C flow. + */ +template<class TypeTag> +class ThreePThreeCLocalResidual: 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, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum { + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + + conti0EqIdx = Indices::conti0EqIdx,//!< Index of the mass conservation equation for the water component + conti1EqIdx = Indices::conti1EqIdx,//!< Index of the mass conservation equation for the contaminant component + conti2EqIdx = Indices::conti2EqIdx,//!< Index of the mass conservation equation for the gas component + + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + gPhaseIdx = Indices::gPhaseIdx, + + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx, + gCompIdx = Indices::gCompIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + +public: + /*! + * \brief Evaluate the amount of all conservation quantities + * (e.g. phase mass) within a sub-control volume. + * + * The result should be averaged over the volume (e.g. phase mass + * inside a sub control volume divided by the volume) + * + * \param storage The mass of the component 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, const 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]; + + // compute storage term of all components within all phases + storage = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + storage[conti0EqIdx + compIdx] += + volVars.porosity() + * volVars.saturation(phaseIdx) + * volVars.molarDensity(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx); + } + } + } + + /*! + * \brief Evaluates the total flux of all conservation quantities + * 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 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, const int fIdx, const bool onBoundary=false) const + { + FluxVariables fluxVars(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_(), + onBoundary); + + flux = 0; + asImp_()->computeAdvectiveFlux(flux, fluxVars); + asImp_()->computeDiffusiveFlux(flux, fluxVars); + } + + /*! + * \brief Evaluates the advective mass flux of all components 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 + { + Scalar massUpwindWeight = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); + + //////// + // advective fluxes of all components in all phases + //////// + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // 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)); + + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + // add advective flux of current component in current + // phase + // if alpha > 0 and alpha < 1 then both upstream and downstream + // nodes need their contribution + // if alpha == 1 (which is mostly the case) then, the downstream + // node is not evaluated + int eqIdx = conti0EqIdx + compIdx; + flux[eqIdx] += fluxVars.volumeFlux(phaseIdx) + * (massUpwindWeight + * up.molarDensity(phaseIdx) + * up.moleFraction(phaseIdx, compIdx) + + + (1.0 - massUpwindWeight) + * dn.molarDensity(phaseIdx) + * dn.moleFraction(phaseIdx, compIdx)); + } + } + } + + /*! + * \brief Adds the diffusive mass flux of all components over + * a face of a subcontrol volume. + * + * \param flux The diffusive flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current SCV + */ + + void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + { + // TODO: reference!? Dune::FieldMatrix<Scalar, numPhases, numComponents> averagedPorousDiffCoeffMatrix = fluxVars.porousDiffCoeff(); + // add diffusive flux of gas component in liquid phase + Scalar tmp = - fluxVars.porousDiffCoeff()[wPhaseIdx][gCompIdx] * fluxVars.molarDensity(wPhaseIdx); + tmp *= (fluxVars.moleFractionCompGGrad(wPhaseIdx) * fluxVars.face().normal); + Scalar jGW = tmp; + + tmp = - fluxVars.porousDiffCoeff()[wPhaseIdx][nCompIdx] * fluxVars.molarDensity(wPhaseIdx); + tmp *= (fluxVars.moleFractionCompNGrad(wPhaseIdx) * fluxVars.face().normal); + Scalar jNW = tmp; + + Scalar jWW = -(jGW+jNW); + + tmp = - fluxVars.porousDiffCoeff()[gPhaseIdx][wCompIdx] * fluxVars.molarDensity(gPhaseIdx); + tmp *= (fluxVars.moleFractionCompWGrad(gPhaseIdx) * fluxVars.face().normal); + Scalar jWG = tmp; + + tmp = - fluxVars.porousDiffCoeff()[gPhaseIdx][nCompIdx] * fluxVars.molarDensity(gPhaseIdx); + tmp *= (fluxVars.moleFractionCompNGrad(gPhaseIdx) * fluxVars.face().normal); + Scalar jNG = tmp; + + Scalar jGG = -(jWG+jNG); + + tmp = - fluxVars.porousDiffCoeff()[nPhaseIdx][wCompIdx] * fluxVars.molarDensity(nPhaseIdx); + tmp *= (fluxVars.moleFractionCompWGrad(nPhaseIdx) * fluxVars.face().normal); + Scalar jWN = tmp; + + tmp = - fluxVars.porousDiffCoeff()[nPhaseIdx][gCompIdx] * fluxVars.molarDensity(nPhaseIdx); + tmp *= (fluxVars.moleFractionCompGGrad(nPhaseIdx) * fluxVars.face().normal); + Scalar jGN = tmp; + + Scalar jNN = -(jGN+jWN); + + flux[conti0EqIdx] += jWW+jWG+jWN; + flux[conti1EqIdx] += jNW+jNG+jNN; + flux[conti2EqIdx] += jGW+jGG+jGN; + } + +protected: + Implementation *asImp_() + { + return static_cast<Implementation *> (this); + } + + const Implementation *asImp_() const + { + return static_cast<const Implementation *> (this); + } +}; + +} // end namespace + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/model.hh b/dumux/porousmediumflow/3p3c/implicit/model.hh new file mode 100644 index 0000000000..6801ed9d4d --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/model.hh @@ -0,0 +1,1020 @@ +// -*- 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 three-phase three-component + * flow model. + * + * The model is designed for simulating three fluid phases with water, gas, and + * a liquid contaminant (NAPL - non-aqueous phase liquid) + */ +#ifndef DUMUX_3P3C_MODEL_HH +#define DUMUX_3P3C_MODEL_HH + +#include <dumux/porousmediumflow/implicit/velocityoutput.hh> +#include "properties.hh" + +namespace Dumux +{ +/*! + * \ingroup ThreePThreeCModel + * \brief Adaption of the fully implicit scheme to the three-phase three-component + * flow model. + * + * This model implements three-phase three-component flow of three fluid phases + * \f$\alpha \in \{ water, gas, NAPL \}\f$ each composed of up to three components + * \f$\kappa \in \{ water, air, contaminant \}\f$. The standard multiphase Darcy + * approach is used as the equation for the conservation of momentum: + * \f[ + v_\alpha = - \frac{k_{r\alpha}}{\mu_\alpha} \mathbf{K} + \left(\textbf{grad}\, p_\alpha - \varrho_{\alpha} \mbox{\bf g} \right) + * \f] + * + * By inserting this into the equations for the conservation of the + * components, one transport equation for each component is obtained as + * \f{eqnarray*} + && \phi \frac{\partial (\sum_\alpha \varrho_{\alpha,mol} x_\alpha^\kappa + S_\alpha )}{\partial t} + - \sum\limits_\alpha \text{div} \left\{ \frac{k_{r\alpha}}{\mu_\alpha} + \varrho_{\alpha,mol} x_\alpha^\kappa \mathbf{K} + (\textbf{grad}\, p_\alpha - \varrho_{\alpha,mass} \mbox{\bf g}) \right\} + \nonumber \\ + \nonumber \\ + && - \sum\limits_\alpha \text{div} \left\{ D_\text{pm}^\kappa \varrho_{\alpha,mol} + \textbf{grad} x^\kappa_{\alpha} \right\} + - q^\kappa = 0 \qquad \forall \kappa , \; \forall \alpha + \f} + * + * Note that these balance equations are molar. + * + * 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 model uses commonly applied auxiliary conditions like + * \f$S_w + S_n + S_g = 1\f$ for the saturations and + * \f$x^w_\alpha + x^a_\alpha + x^c_\alpha = 1\f$ for the mole fractions. + * Furthermore, the phase pressures are related to each other via + * capillary pressures between the fluid phases, which are functions of + * the saturation, e.g. according to the approach of Parker et al. + * + * The used primary variables are dependent on the locally present fluid phases. + * An adaptive primary variable switch is included. The phase state is stored for all nodes + * of the system. The following cases can be distinguished: + * <ul> + * <li> All three phases are present: Primary variables are two saturations \f$(S_w\f$ and \f$S_n)\f$, + * and a pressure, in this case \f$p_g\f$. </li> + * <li> Only the water phase is present: Primary variables are now the mole fractions of air and + * contaminant in the water phase \f$(x_w^a\f$ and \f$x_w^c)\f$, as well as the gas pressure, which is, + * of course, in a case where only the water phase is present, just the same as the water pressure. </li> + * <li> Gas and NAPL phases are present: Primary variables \f$(S_n\f$, \f$x_g^w\f$, \f$p_g)\f$. </li> + * <li> Water and NAPL phases are present: Primary variables \f$(S_n\f$, \f$x_w^a\f$, \f$p_g)\f$. </li> + * <li> Only gas phase is present: Primary variables \f$(x_g^w\f$, \f$x_g^c\f$, \f$p_g)\f$. </li> + * <li> Water and gas phases are present: Primary variables \f$(S_w\f$, \f$x_w^g\f$, \f$p_g)\f$. </li> + * </ul> + */ +template<class TypeTag> +class ThreePThreeCModel: public GET_PROP_TYPE(TypeTag, BaseModel) +{ + typedef typename GET_PROP_TYPE(TypeTag, BaseModel) ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum { + dim = GridView::dimension, + dimWorld = GridView::dimensionworld, + + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + + switch1Idx = Indices::switch1Idx, + switch2Idx = Indices::switch2Idx, + + + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + gPhaseIdx = Indices::gPhaseIdx, + + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx, + gCompIdx = Indices::gCompIdx, + + threePhases = Indices::threePhases, + wPhaseOnly = Indices::wPhaseOnly, + gnPhaseOnly = Indices::gnPhaseOnly, + wnPhaseOnly = Indices::wnPhaseOnly, + gPhaseOnly = Indices::gPhaseOnly, + wgPhaseOnly = Indices::wgPhaseOnly + + }; + + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + +public: + /*! + * \brief Initialize the static data with the initial solution. + * + * \param problem The problem to be solved + */ + void init(Problem &problem) + { + ParentType::init(problem); + + staticDat_.resize(this->numDofs()); + + setSwitched_(false); + + if (isBox) + { + for (const auto& vertex : Dune::vertices(this->gridView_())) + { + int vIdxGlobal = this->dofMapper().index(vertex); + + const GlobalPosition &globalPos = vertex.geometry().corner(0); + + // initialize phase presence + staticDat_[vIdxGlobal].phasePresence + = this->problem_().initialPhasePresence(vertex, vIdxGlobal, + globalPos); + staticDat_[vIdxGlobal].wasSwitched = false; + + staticDat_[vIdxGlobal].oldPhasePresence + = staticDat_[vIdxGlobal].phasePresence; + } + } + else + { + for (const auto& element : Dune::elements(this->gridView_())) + { + int eIdxGlobal = this->dofMapper().index(element); + const GlobalPosition &globalPos = element.geometry().center(); + + // initialize phase presence + staticDat_[eIdxGlobal].phasePresence + = this->problem_().initialPhasePresence(*this->gridView_().template begin<dim> (), + eIdxGlobal, globalPos); + staticDat_[eIdxGlobal].wasSwitched = false; + + staticDat_[eIdxGlobal].oldPhasePresence + = staticDat_[eIdxGlobal].phasePresence; + } + } + } + + /*! + * \brief Compute the total storage inside one phase of all + * conservation quantities. + * + * \param storage Contains the storage of each component for one phase + * \param phaseIdx The phase index + */ + void globalPhaseStorage(PrimaryVariables &storage, const int phaseIdx) + { + storage = 0; + + for (const auto& element : Dune::elements(this->gridView_())) { + if(element.partitionType() == Dune::InteriorEntity) + { + this->localResidual().evalPhaseStorage(element, phaseIdx); + + for (unsigned int i = 0; i < this->localResidual().storageTerm().size(); ++i) + storage += this->localResidual().storageTerm()[i]; + } + } + if (this->gridView_().comm().size() > 1) + storage = this->gridView_().comm().sum(storage); + } + + + /*! + * \brief Called by the update() method if applying the newton + * method was unsuccessful. + */ + void updateFailed() + { + ParentType::updateFailed(); + + setSwitched_(false); + resetPhasePresence_(); + }; + + /*! + * \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() + { + ParentType::advanceTimeLevel(); + + // update the phase state + updateOldPhasePresence_(); + setSwitched_(false); + } + + /*! + * \brief Return true if the primary variables were switched for + * at least one vertex after the last timestep. + */ + bool switched() const + { + return switchFlag_; + } + + /*! + * \brief Returns the phase presence of the current or the old solution of a degree of freedom. + * + * \param dofIdxGlobal The global index of the degree of freedom + * \param oldSol Evaluate function with solution of current or previous time step + */ + int phasePresence(int dofIdxGlobal, bool oldSol) const + { + return + oldSol + ? staticDat_[dofIdxGlobal].oldPhasePresence + : staticDat_[dofIdxGlobal].phasePresence; + } + + /*! + * \brief Append all quantities of interest which can be derived + * from the solution of the current time step to the VTK + * writer. + * + * \param sol The solution vector + * \param writer The writer for multi-file VTK datasets + */ + template<class MultiWriter> + void addOutputVtkFields(const SolutionVector &sol, + MultiWriter &writer) + { + typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<double, dimWorld> > VectorField; + + // get the number of degrees of freedom + unsigned numDofs = this->numDofs(); + + // create the required scalar fields + ScalarField *saturation[numPhases]; + ScalarField *pressure[numPhases]; + ScalarField *density[numPhases]; + + for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { + saturation[phaseIdx] = writer.allocateManagedBuffer(numDofs); + pressure[phaseIdx] = writer.allocateManagedBuffer(numDofs); + density[phaseIdx] = writer.allocateManagedBuffer(numDofs); + } + + ScalarField *phasePresence = writer.allocateManagedBuffer (numDofs); + ScalarField *moleFraction[numPhases][numComponents]; + for (int i = 0; i < numPhases; ++i) + for (int j = 0; j < numComponents; ++j) + moleFraction[i][j] = writer.allocateManagedBuffer (numDofs); + ScalarField *temperature = writer.allocateManagedBuffer (numDofs); + ScalarField *poro = writer.allocateManagedBuffer(numDofs); + VectorField *velocityN = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); + VectorField *velocityW = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); + VectorField *velocityG = writer.template allocateManagedBuffer<double, dimWorld>(numDofs); + ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_()); + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + // initialize velocity fields + for (unsigned int i = 0; i < numDofs; ++i) + { + (*velocityN)[i] = Scalar(0); + (*velocityW)[i] = Scalar(0); + (*velocityG)[i] = Scalar(0); + } + } + + unsigned numElements = this->gridView_().size(0); + ScalarField *rank = writer.allocateManagedBuffer (numElements); + + for (const auto& element : Dune::elements(this->gridView_())) + { + if(element.partitionType() == Dune::InteriorEntity) + { + int eIdx = this->problem_().elementMapper().index(element); + (*rank)[eIdx] = this->gridView_().comm().rank(); + + FVElementGeometry fvGeometry; + fvGeometry.update(this->gridView_(), element); + + + ElementVolumeVariables elemVolVars; + elemVolVars.update(this->problem_(), + element, + fvGeometry, + false /* oldSol? */); + + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); + + for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { + (*saturation[phaseIdx])[dofIdxGlobal] = elemVolVars[scvIdx].saturation(phaseIdx); + (*pressure[phaseIdx])[dofIdxGlobal] = elemVolVars[scvIdx].pressure(phaseIdx); + (*density[phaseIdx])[dofIdxGlobal] = elemVolVars[scvIdx].density(phaseIdx); + } + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + for (int compIdx = 0; compIdx < numComponents; ++compIdx) { + (*moleFraction[phaseIdx][compIdx])[dofIdxGlobal] = + elemVolVars[scvIdx].moleFraction(phaseIdx, + compIdx); + + Valgrind::CheckDefined((*moleFraction[phaseIdx][compIdx])[dofIdxGlobal]); + } + } + + (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity(); + (*temperature)[dofIdxGlobal] = elemVolVars[scvIdx].temperature(); + (*phasePresence)[dofIdxGlobal] = staticDat_[dofIdxGlobal].phasePresence; + } + + // velocity output + velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx); + velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx); + velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, gPhaseIdx); + } + } + + writer.attachDofData(*saturation[wPhaseIdx], "Sw", isBox); + writer.attachDofData(*saturation[nPhaseIdx], "Sn", isBox); + writer.attachDofData(*saturation[gPhaseIdx], "Sg", isBox); + writer.attachDofData(*pressure[wPhaseIdx], "pw", isBox); + writer.attachDofData(*pressure[nPhaseIdx], "pn", isBox); + writer.attachDofData(*pressure[gPhaseIdx], "pg", isBox); + writer.attachDofData(*density[wPhaseIdx], "rhow", isBox); + writer.attachDofData(*density[nPhaseIdx], "rhon", isBox); + writer.attachDofData(*density[gPhaseIdx], "rhog", isBox); + + for (int i = 0; i < numPhases; ++i) + { + for (int j = 0; j < numComponents; ++j) + { + std::ostringstream oss; + oss << "x^" + << FluidSystem::componentName(j) + << "_" + << FluidSystem::phaseName(i); + writer.attachDofData(*moleFraction[i][j], oss.str().c_str(), isBox); + } + } + writer.attachDofData(*poro, "porosity", isBox); + writer.attachDofData(*temperature, "temperature", isBox); + writer.attachDofData(*phasePresence, "phase presence", isBox); + + if (velocityOutput.enableOutput()) // check if velocity output is demanded + { + writer.attachDofData(*velocityW, "velocityW", isBox, dim); + writer.attachDofData(*velocityN, "velocityN", isBox, dim); + writer.attachDofData(*velocityG, "velocityG", isBox, dim); + } + + writer.attachCellData(*rank, "process rank"); + } + + /*! + * \brief Write the current solution to a restart file. + * + * \param outStream The output stream of one entity for the restart file + * \param entity The entity, either a vertex or an element + */ + template<class Entity> + void serializeEntity(std::ostream &outStream, const Entity &entity) + { + // write primary variables + ParentType::serializeEntity(outStream, entity); + + int dofIdxGlobal = this->dofMapper().index(entity); + + if (!outStream.good()) + DUNE_THROW(Dune::IOError, "Could not serialize entity " << dofIdxGlobal); + + outStream << staticDat_[dofIdxGlobal].phasePresence << " "; + } + + /*! + * \brief Reads the current solution from a restart file. + * + * \param inStream The input stream of one entity from the restart file + * \param entity The entity, either a vertex or an element + */ + template<class Entity> + void deserializeEntity(std::istream &inStream, const Entity &entity) + { + // read primary variables + ParentType::deserializeEntity(inStream, entity); + + // read phase presence + int dofIdxGlobal = this->dofMapper().index(entity); + + if (!inStream.good()) + DUNE_THROW(Dune::IOError, + "Could not deserialize entity " << dofIdxGlobal); + + inStream >> staticDat_[dofIdxGlobal].phasePresence; + staticDat_[dofIdxGlobal].oldPhasePresence + = staticDat_[dofIdxGlobal].phasePresence; + + } + + /*! + * \brief Update the static data of all vertices in the grid. + * + * \param curGlobalSol The current global solution + * \param oldGlobalSol The previous global solution + */ + void updateStaticData(SolutionVector &curGlobalSol, + const SolutionVector &oldGlobalSol) + { + bool wasSwitched = false; + int succeeded; + try { + + for (unsigned i = 0; i < staticDat_.size(); ++i) + staticDat_[i].visited = false; + + FVElementGeometry fvGeometry; + static VolumeVariables volVars; + for (const auto& element : Dune::elements(this->gridView_())) + { + fvGeometry.update(this->gridView_(), element); + for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx) + { + int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim); + + if (staticDat_[dofIdxGlobal].visited) + continue; + + staticDat_[dofIdxGlobal].visited = true; + volVars.update(curGlobalSol[dofIdxGlobal], + this->problem_(), + element, + fvGeometry, + scvIdx, + false); + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (primaryVarSwitch_(curGlobalSol, + volVars, + dofIdxGlobal, + globalPos)) + { + this->jacobianAssembler().markDofRed(dofIdxGlobal); + wasSwitched = true; + } + } + } + succeeded = 1; + } + catch (Dumux::NumericalProblem &e) + { + std::cout << "\n" + << "Rank " << this->problem_().gridView().comm().rank() + << " caught an exception while updating the static data." << e.what() + << "\n"; + succeeded = 0; + } + //make sure that all processes succeeded. If not throw a NumericalProblem to decrease the time step size. + if (this->gridView_().comm().size() > 1) + succeeded = this->gridView_().comm().min(succeeded); + + if (!succeeded) { + DUNE_THROW(NumericalProblem, + "A process did not succeed in updating the static data."); + return; + } + + // make sure that if there was a variable switch in an + // other partition we will also set the switch flag + // for our partition. + if (this->gridView_().comm().size() > 1) + wasSwitched = this->gridView_().comm().max(wasSwitched); + + setSwitched_(wasSwitched); + } + +protected: + /*! + * \brief Data which is attached to each vertex and is not only + * stored locally. + */ + struct StaticVars + { + int phasePresence; + bool wasSwitched; + + int oldPhasePresence; + bool visited; + }; + + /*! + * \brief Reset the current phase presence of all vertices to the old one. + * + * This is done after an update failed. + */ + void resetPhasePresence_() + { + for (unsigned int i = 0; i < this->numDofs(); ++i) + { + staticDat_[i].phasePresence + = staticDat_[i].oldPhasePresence; + staticDat_[i].wasSwitched = false; + } + } + + /*! + * \brief Set the old phase of all verts state to the current one. + */ + void updateOldPhasePresence_() + { + for (unsigned int i = 0; i < this->numDofs(); ++i) + { + staticDat_[i].oldPhasePresence + = staticDat_[i].phasePresence; + staticDat_[i].wasSwitched = false; + } + } + + /*! + * \brief Set whether there was a primary variable switch after in + * the last timestep. + */ + void setSwitched_(bool yesno) + { + switchFlag_ = yesno; + } + + // perform variable switch at a vertex; Returns true if a + // variable switch was performed. + bool primaryVarSwitch_(SolutionVector &globalSol, + const VolumeVariables &volVars, + int dofIdxGlobal, + const GlobalPosition &globalPos) + { + // evaluate primary variable switch + bool wouldSwitch = false; + int phasePresence = staticDat_[dofIdxGlobal].phasePresence; + int newPhasePresence = phasePresence; + + // check if a primary var switch is necessary + if (phasePresence == threePhases) + { + Scalar Smin = 0; + if (staticDat_[dofIdxGlobal].wasSwitched) + Smin = -0.01; + + if (volVars.saturation(gPhaseIdx) <= Smin) + { + wouldSwitch = true; + // gas phase disappears + std::cout << "Gas phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sg: " + << volVars.saturation(gPhaseIdx) << std::endl; + newPhasePresence = wnPhaseOnly; + + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(wPhaseIdx, gCompIdx); + } + else if (volVars.saturation(wPhaseIdx) <= Smin) + { + wouldSwitch = true; + // water phase disappears + std::cout << "Water phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sw: " + << volVars.saturation(wPhaseIdx) << std::endl; + newPhasePresence = gnPhaseOnly; + + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(gPhaseIdx, wCompIdx); + } + else if (volVars.saturation(nPhaseIdx) <= Smin) + { + wouldSwitch = true; + // NAPL phase disappears + std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sn: " + << volVars.saturation(nPhaseIdx) << std::endl; + newPhasePresence = wgPhaseOnly; + + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(gPhaseIdx, nCompIdx); + } + } + else if (phasePresence == wPhaseOnly) + { + bool gasFlag = 0; + bool nonwettingFlag = 0; + // calculate fractions of the partial pressures in the + // hypothetical gas phase + Scalar xwg = volVars.moleFraction(gPhaseIdx, wCompIdx); + Scalar xgg = volVars.moleFraction(gPhaseIdx, gCompIdx); + Scalar xng = volVars.moleFraction(gPhaseIdx, nCompIdx); + /* take care: + for xgg in case wPhaseOnly we compute xgg=henry_air*x2w + for xwg in case wPhaseOnly we compute xwg=pwsat + for xng in case wPhaseOnly we compute xng=henry_NAPL*x1w + */ + + Scalar xgMax = 1.0; + if (xwg + xgg + xng > xgMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xgMax *= 1.02; + + // if the sum of the mole fractions would be larger than + // 100%, gas phase appears + if (xwg + xgg + xng > xgMax) + { + // gas phase appears + std::cout << "gas phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xwg + xgg + xng: " + << xwg + xgg + xng << std::endl; + gasFlag = 1; + } + + // calculate fractions in the hypothetical NAPL phase + Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); + /* take care: + for xnn in case wPhaseOnly we compute xnn=henry_mesitylene*x1w, + where a hypothetical gas pressure is assumed for the Henry + x0n is set to NULL (all NAPL phase is dirty) + x2n is set to NULL (all NAPL phase is dirty) + */ + + Scalar xnMax = 1.0; + if (xnn > xnMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xnMax *= 1.02; + + // if the sum of the hypothetical mole fractions would be larger than + // 100%, NAPL phase appears + if (xnn > xnMax) + { + // NAPL phase appears + std::cout << "NAPL phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xnn: " + << xnn << std::endl; + nonwettingFlag = 1; + } + + if ((gasFlag == 1) && (nonwettingFlag == 0)) + { + newPhasePresence = wgPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] = 0.9999; + globalSol[dofIdxGlobal][switch2Idx] = 0.0001; + } + else if ((gasFlag == 1) && (nonwettingFlag == 1)) + { + newPhasePresence = threePhases; + globalSol[dofIdxGlobal][switch1Idx] = 0.9999; + globalSol[dofIdxGlobal][switch2Idx] = 0.0001; + } + else if ((gasFlag == 0) && (nonwettingFlag == 1)) + { + newPhasePresence = wnPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(wPhaseIdx, gCompIdx); + globalSol[dofIdxGlobal][switch2Idx] = 0.0001; + } + } + else if (phasePresence == gnPhaseOnly) + { + bool nonwettingFlag = 0; + bool wettingFlag = 0; + + Scalar Smin = 0.0; + if (staticDat_[dofIdxGlobal].wasSwitched) + Smin = -0.01; + + if (volVars.saturation(nPhaseIdx) <= Smin) + { + wouldSwitch = true; + // NAPL phase disappears + std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sn: " + << volVars.saturation(nPhaseIdx) << std::endl; + nonwettingFlag = 1; + } + + + // calculate fractions of the hypothetical water phase + Scalar xww = volVars.moleFraction(wPhaseIdx, wCompIdx); + /* + take care:, xww, if no water is present, then take xww=xwg*pg/pwsat . + If this is larger than 1, then water appears + */ + Scalar xwMax = 1.0; + if (xww > xwMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xwMax *= 1.02; + + // if the sum of the mole fractions would be larger than + // 100%, gas phase appears + if (xww > xwMax) + { + // water phase appears + std::cout << "water phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : " + << xww << std::endl; + wettingFlag = 1; + } + + if ((wettingFlag == 1) && (nonwettingFlag == 0)) + { + newPhasePresence = threePhases; + globalSol[dofIdxGlobal][switch1Idx] = 0.0001; + globalSol[dofIdxGlobal][switch2Idx] = volVars.saturation(nPhaseIdx); + } + else if ((wettingFlag == 1) && (nonwettingFlag == 1)) + { + newPhasePresence = wgPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] = 0.0001; + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(gPhaseIdx, nCompIdx); + } + else if ((wettingFlag == 0) && (nonwettingFlag == 1)) + { + newPhasePresence = gPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(gPhaseIdx, wCompIdx); + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(gPhaseIdx, nCompIdx); + } + } + else if (phasePresence == wnPhaseOnly) + { + bool nonwettingFlag = 0; + bool gasFlag = 0; + + Scalar Smin = 0.0; + if (staticDat_[dofIdxGlobal].wasSwitched) + Smin = -0.01; + + if (volVars.saturation(nPhaseIdx) <= Smin) + { + wouldSwitch = true; + // NAPL phase disappears + std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sn: " + << volVars.saturation(nPhaseIdx) << std::endl; + nonwettingFlag = 1; + } + + // calculate fractions of the partial pressures in the + // hypothetical gas phase + Scalar xwg = volVars.moleFraction(gPhaseIdx, wCompIdx); + Scalar xgg = volVars.moleFraction(gPhaseIdx, gCompIdx); + Scalar xng = volVars.moleFraction(gPhaseIdx, nCompIdx); + /* take care: + for xgg in case wPhaseOnly we compute xgg=henry_air*x2w + for xwg in case wPhaseOnly we compute xwg=pwsat + for xng in case wPhaseOnly we compute xng=henry_NAPL*x1w + */ + Scalar xgMax = 1.0; + if (xwg + xgg + xng > xgMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xgMax *= 1.02; + + // if the sum of the mole fractions would be larger than + // 100%, gas phase appears + if (xwg + xgg + xng > xgMax) + { + // gas phase appears + std::cout << "gas phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xwg + xgg + xng: " + << xwg + xgg + xng << std::endl; + gasFlag = 1; + } + + if ((gasFlag == 1) && (nonwettingFlag == 0)) + { + newPhasePresence = threePhases; + globalSol[dofIdxGlobal][switch1Idx] = volVars.saturation(wPhaseIdx); + globalSol[dofIdxGlobal][switch2Idx] = volVars.saturation(nPhaseIdx); + } + else if ((gasFlag == 1) && (nonwettingFlag == 1)) + { + newPhasePresence = wgPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] = volVars.saturation(wPhaseIdx); + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(gPhaseIdx, nCompIdx); + } + else if ((gasFlag == 0) && (nonwettingFlag == 1)) + { + newPhasePresence = wPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(wPhaseIdx, gCompIdx); + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(wPhaseIdx, nCompIdx); + } + } + else if (phasePresence == gPhaseOnly) + { + bool nonwettingFlag = 0; + bool wettingFlag = 0; + + // calculate fractions in the hypothetical NAPL phase + Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); + /* + take care:, xnn, if no NAPL phase is there, take xnn=xng*pg/pcsat + if this is larger than 1, then NAPL appears + */ + + Scalar xnMax = 1.0; + if (xnn > xnMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xnMax *= 1.02; + + // if the sum of the hypothetical mole fraction would be larger than + // 100%, NAPL phase appears + if (xnn > xnMax) + { + // NAPL phase appears + std::cout << "NAPL phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xnn: " + << xnn << std::endl; + nonwettingFlag = 1; + } + // calculate fractions of the hypothetical water phase + Scalar xww = volVars.moleFraction(wPhaseIdx, wCompIdx); + /* + take care:, xww, if no water is present, then take xww=xwg*pg/pwsat . + If this is larger than 1, then water appears + */ + Scalar xwMax = 1.0; + if (xww > xwMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xwMax *= 1.02; + + // if the sum of the mole fractions would be larger than + // 100%, gas phase appears + if (xww > xwMax) + { + // water phase appears + std::cout << "water phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : " + << xww << std::endl; + wettingFlag = 1; + } + if ((wettingFlag == 1) && (nonwettingFlag == 0)) + { + newPhasePresence = wgPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] = 0.0001; + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(gPhaseIdx, nCompIdx); + } + else if ((wettingFlag == 1) && (nonwettingFlag == 1)) + { + newPhasePresence = threePhases; + globalSol[dofIdxGlobal][switch1Idx] = 0.0001; + globalSol[dofIdxGlobal][switch2Idx] = 0.0001; + } + else if ((wettingFlag == 0) && (nonwettingFlag == 1)) + { + newPhasePresence = gnPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(gPhaseIdx, wCompIdx); + globalSol[dofIdxGlobal][switch2Idx] = 0.0001; + } + } + else if (phasePresence == wgPhaseOnly) + { + bool nonwettingFlag = 0; + bool gasFlag = 0; + bool wettingFlag = 0; + + // get the fractions in the hypothetical NAPL phase + Scalar xnn = volVars.moleFraction(nPhaseIdx, nCompIdx); + + // take care: if the NAPL phase is not present, take + // xnn=xng*pg/pcsat if this is larger than 1, then NAPL + // appears + Scalar xnMax = 1.0; + if (xnn > xnMax) + wouldSwitch = true; + if (staticDat_[dofIdxGlobal].wasSwitched) + xnMax *= 1.02; + + // if the sum of the hypothetical mole fraction would be larger than + // 100%, NAPL phase appears + if (xnn > xnMax) + { + // NAPL phase appears + std::cout << "NAPL phase appears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", xnn: " + << xnn << std::endl; + nonwettingFlag = 1; + } + + Scalar Smin = -1.e-6; + if (staticDat_[dofIdxGlobal].wasSwitched) + Smin = -0.01; + + if (volVars.saturation(gPhaseIdx) <= Smin) + { + wouldSwitch = true; + // gas phase disappears + std::cout << "Gas phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sg: " + << volVars.saturation(gPhaseIdx) << std::endl; + gasFlag = 1; + } + + Smin = 0.0; + if (staticDat_[dofIdxGlobal].wasSwitched) + Smin = -0.01; + + if (volVars.saturation(wPhaseIdx) <= Smin) + { + wouldSwitch = true; + // gas phase disappears + std::cout << "Water phase disappears at vertex " << dofIdxGlobal + << ", coordinates: " << globalPos << ", sw: " + << volVars.saturation(wPhaseIdx) << std::endl; + wettingFlag = 1; + } + + if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 1)) + { + newPhasePresence = gnPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(gPhaseIdx, wCompIdx); + globalSol[dofIdxGlobal][switch2Idx] = 0.0001; + } + else if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 0)) + { + newPhasePresence = threePhases; + globalSol[dofIdxGlobal][switch1Idx] = volVars.saturation(wPhaseIdx); + globalSol[dofIdxGlobal][switch2Idx] = 0.0; + } + else if ((gasFlag == 1) && (nonwettingFlag == 0) && (wettingFlag == 0)) + { + newPhasePresence = wPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(wPhaseIdx, gCompIdx); + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(wPhaseIdx, nCompIdx); + } + else if ((gasFlag == 0) && (nonwettingFlag == 0) && (wettingFlag == 1)) + { + newPhasePresence = gPhaseOnly; + globalSol[dofIdxGlobal][switch1Idx] + = volVars.moleFraction(gPhaseIdx, wCompIdx); + globalSol[dofIdxGlobal][switch2Idx] + = volVars.moleFraction(gPhaseIdx, nCompIdx); + } + } + + staticDat_[dofIdxGlobal].phasePresence = newPhasePresence; + staticDat_[dofIdxGlobal].wasSwitched = wouldSwitch; + return phasePresence != newPhasePresence; + } + + // parameters given in constructor + std::vector<StaticVars> staticDat_; + bool switchFlag_; +}; + +} + +#include "propertydefaults.hh" + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/newtoncontroller.hh b/dumux/porousmediumflow/3p3c/implicit/newtoncontroller.hh new file mode 100644 index 0000000000..053b2cb01f --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/newtoncontroller.hh @@ -0,0 +1,86 @@ +// -*- 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 A three-phase three-component 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_3P3C_NEWTON_CONTROLLER_HH +#define DUMUX_3P3C_NEWTON_CONTROLLER_HH + +#include "properties.hh" + +#include <dumux/nonlinear/newtoncontroller.hh> + +namespace Dumux { +/*! + * \ingroup Newton + * \ingroup ThreePThreeCModel + * \brief A three-phase three-component 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. + */ +template <class TypeTag> +class ThreePThreeCNewtonController : public NewtonController<TypeTag> +{ + typedef NewtonController<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + +public: + ThreePThreeCNewtonController(const Problem &problem) + : ParentType(problem) + {}; + + + /*! + * \brief Called after each Newton update + * + * \param uCurrentIter The current global solution vector + * \param uLastIter The previous global solution vector + */ + void newtonEndStep(SolutionVector &uCurrentIter, + const SolutionVector &uLastIter) + { + // call the method of the base class + this->method().model().updateStaticData(uCurrentIter, uLastIter); + ParentType::newtonEndStep(uCurrentIter, uLastIter); + } + + + /*! + * \brief Returns true if the current solution can be considered to + * be accurate enough + */ + bool newtonConverged() + { + if (this->method().model().switched()) + return false; + + return ParentType::newtonConverged(); + }; +}; +} + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/properties.hh b/dumux/porousmediumflow/3p3c/implicit/properties.hh new file mode 100644 index 0000000000..52a2762e8c --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/properties.hh @@ -0,0 +1,82 @@ +// -*- 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 ThreePThreeCModel + */ +/*! + * \file + * + * \brief Defines the properties required for the three-phase three-component + * fully implicit model. + */ +#ifndef DUMUX_3P3C_PROPERTIES_HH +#define DUMUX_3P3C_PROPERTIES_HH + +#include <dumux/implicit/box/properties.hh> +#include <dumux/implicit/cellcentered/properties.hh> +#include <dumux/porousmediumflow/nonisothermal/implicit/properties.hh> + + +namespace Dumux +{ + +namespace Properties +{ +////////////////////////////////////////////////////////////////// +// Type tags +////////////////////////////////////////////////////////////////// + +//! The type tags for the implicit three-phase three-component problems +NEW_TYPE_TAG(ThreePThreeC); +NEW_TYPE_TAG(BoxThreePThreeC, INHERITS_FROM(BoxModel, ThreePThreeC)); +NEW_TYPE_TAG(CCThreePThreeC, INHERITS_FROM(CCModel, ThreePThreeC)); + +//! The type tags for the corresponding non-isothermal problems +NEW_TYPE_TAG(ThreePThreeCNI, INHERITS_FROM(ThreePThreeC, NonIsothermal)); +NEW_TYPE_TAG(BoxThreePThreeCNI, INHERITS_FROM(BoxModel, ThreePThreeCNI)); +NEW_TYPE_TAG(CCThreePThreeCNI, INHERITS_FROM(CCModel, ThreePThreeCNI)); + +////////////////////////////////////////////////////////////////// +// Property tags +////////////////////////////////////////////////////////////////// + +NEW_PROP_TAG(NumPhases); //!< Number of fluid phases in the system +NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system +NEW_PROP_TAG(Indices); //!< Enumerations for the model +NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters +NEW_PROP_TAG(FluidSystem); //!< Type of the multi-component relations +NEW_PROP_TAG(FluidState); //!< Type of the fluid state to be used + +NEW_PROP_TAG(MaterialLaw); //!< The material law which ought to be used (extracted from the spatial parameters) +NEW_PROP_TAG(MaterialLawParams); //!< The parameters of the material law (extracted from the spatial parameters) +NEW_PROP_TAG(EffectiveDiffusivityModel); //!< The employed model for the computation of the effective diffusivity + +NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem +NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The value of the upwind parameter for the mobility +NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation +NEW_PROP_TAG(UseConstraintSolver); //!< Determines whether a constraint solver should be used explicitly +NEW_PROP_TAG(BaseFluxVariables); //! The base flux variables +NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient +NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output +} +} + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/propertydefaults.hh b/dumux/porousmediumflow/3p3c/implicit/propertydefaults.hh new file mode 100644 index 0000000000..aff1b567da --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/propertydefaults.hh @@ -0,0 +1,210 @@ +// -*- 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 ThreePThreeCModel + * \file + * + * \brief Defines default values for most properties required by the + * three-phase three-component fully implicit model. + */ +#ifndef DUMUX_3P3C_PROPERTY_DEFAULTS_HH +#define DUMUX_3P3C_PROPERTY_DEFAULTS_HH + +#include "indices.hh" + +#include "model.hh" +#include "fluxvariables.hh" +#include "volumevariables.hh" +#include "properties.hh" +#include "newtoncontroller.hh" +#include "localresidual.hh" + +#include <dumux/porousmediumflow/nonisothermal/implicit/propertydefaults.hh> +#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> +#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh> +#include <dumux/material/spatialparams/implicitspatialparams.hh> +#include <dumux/material/fluidmatrixinteractions/3p/thermalconductivitysomerton3p.hh> + +namespace Dumux +{ + +namespace Properties { +////////////////////////////////////////////////////////////////// +// Property values +////////////////////////////////////////////////////////////////// + +/*! + * \brief Set the property for the number of components. + * + * We just forward the number from the fluid system and use an static + * assert to make sure it is 3. + */ +SET_PROP(ThreePThreeC, NumComponents) +{ + private: + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + public: + static const int value = FluidSystem::numComponents; + + static_assert(value == 3, + "Only fluid systems with 3 components are supported by the 3p3c model!"); +}; + +/*! + * \brief Set the property for the number of fluid phases. + * + * We just forward the number from the fluid system and use an static + * assert to make sure it is 3. + */ +SET_PROP(ThreePThreeC, NumPhases) +{ + private: + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + public: + static const int value = FluidSystem::numPhases; + static_assert(value == 3, + "Only fluid systems with 3 phases are supported by the 3p3c model!"); +}; + +/*! + * \brief The fluid state which is used by the volume variables to + * store the thermodynamic state. This should be chosen + * appropriately for the model ((non-)isothermal, equilibrium, ...). + * This can be done in the problem. + */ +SET_PROP(ThreePThreeC, 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_INT_PROP(ThreePThreeC, NumEq, 3); //!< set the number of equations to 2 + +/*! + * \brief Set the property for the material parameters by extracting + * it from the material law. + */ +SET_TYPE_PROP(ThreePThreeC, MaterialLawParams, typename GET_PROP_TYPE(TypeTag, MaterialLaw)::Params); + +//! The local residual function of the conservation equations +SET_TYPE_PROP(ThreePThreeC, LocalResidual, ThreePThreeCLocalResidual<TypeTag>); + +//! Use the 3p3c specific newton controller for the 3p3c model +SET_TYPE_PROP(ThreePThreeC, NewtonController, ThreePThreeCNewtonController<TypeTag>); + +//! the Model property +SET_TYPE_PROP(ThreePThreeC, Model, ThreePThreeCModel<TypeTag>); + +//! the VolumeVariables property +SET_TYPE_PROP(ThreePThreeC, VolumeVariables, ThreePThreeCVolumeVariables<TypeTag>); + +//! the FluxVariables property +SET_TYPE_PROP(ThreePThreeC, FluxVariables, ThreePThreeCFluxVariables<TypeTag>); + +//! define the base flux variables to realize Darcy flow +SET_TYPE_PROP(ThreePThreeC, BaseFluxVariables, ImplicitDarcyFluxVariables<TypeTag>); + +//! the upwind factor for the mobility. +SET_SCALAR_PROP(ThreePThreeC, ImplicitMassUpwindWeight, 1.0); + +//! set default mobility upwind weight to 1.0, i.e. fully upwind +SET_SCALAR_PROP(ThreePThreeC, ImplicitMobilityUpwindWeight, 1.0); + +//! Determines whether a constraint solver should be used explicitly +SET_BOOL_PROP(ThreePThreeC, UseConstraintSolver, false); + +//! The indices required by the isothermal 3p3c model +SET_TYPE_PROP(ThreePThreeC, Indices, ThreePThreeCIndices<TypeTag, /*PVOffset=*/0>); + +//! The spatial parameters to be employed. +//! Use ImplicitSpatialParams by default. +SET_TYPE_PROP(ThreePThreeC, SpatialParams, ImplicitSpatialParams<TypeTag>); + +//! The model after Millington (1961) is used for the effective diffusivity +SET_PROP(ThreePThreeC, EffectiveDiffusivityModel) +{ private : + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + public: + typedef DiffusivityMillingtonQuirk<Scalar> type; +}; + +// disable velocity output by default +SET_BOOL_PROP(ThreePThreeC, VtkAddVelocity, false); + +// enable gravity by default +SET_BOOL_PROP(ThreePThreeC, ProblemEnableGravity, true); + +//! default value for the forchheimer coefficient +// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90. +// Actually the Forchheimer coefficient is also a function of the dimensions of the +// porous medium. Taking it as a constant is only a first approximation +// (Nield, Bejan, Convection in porous media, 2006, p. 10) +SET_SCALAR_PROP(BoxModel, SpatialParamsForchCoeff, 0.55); + +//! Somerton is used as default model to compute the effective thermal heat conductivity +SET_PROP(ThreePThreeCNI, ThermalConductivityModel) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; +public: + typedef ThermalConductivitySomerton<Scalar, Indices> type; +}; + +//! temperature is already written by the isothermal model +SET_BOOL_PROP(ThreePThreeCNI, NiOutputLevel, 0); + +////////////////////////////////////////////////////////////////// +// Property values for isothermal model required for the general non-isothermal model +////////////////////////////////////////////////////////////////// + +// set isothermal Model +SET_TYPE_PROP(ThreePThreeCNI, IsothermalModel, ThreePThreeCModel<TypeTag>); + +// set isothermal FluxVariables +SET_TYPE_PROP(ThreePThreeCNI, IsothermalFluxVariables, ThreePThreeCFluxVariables<TypeTag>); + +//set isothermal VolumeVariables +SET_TYPE_PROP(ThreePThreeCNI, IsothermalVolumeVariables, ThreePThreeCVolumeVariables<TypeTag>); + +//set isothermal LocalResidual +SET_TYPE_PROP(ThreePThreeCNI, IsothermalLocalResidual, ThreePThreeCLocalResidual<TypeTag>); + +//set isothermal Indices +SET_PROP(ThreePThreeCNI, IsothermalIndices) +{ + +public: + typedef ThreePThreeCIndices<TypeTag, /*PVOffset=*/0> type; +}; + +//set isothermal NumEq +SET_INT_PROP(ThreePThreeCNI, IsothermalNumEq, 3); + +} + +} + +#endif diff --git a/dumux/porousmediumflow/3p3c/implicit/volumevariables.hh b/dumux/porousmediumflow/3p3c/implicit/volumevariables.hh new file mode 100644 index 0000000000..4a940147a9 --- /dev/null +++ b/dumux/porousmediumflow/3p3c/implicit/volumevariables.hh @@ -0,0 +1,750 @@ +// -*- 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 Contains the quantities which are constant within a + * finite volume in the three-phase three-component model. + */ +#ifndef DUMUX_3P3C_VOLUME_VARIABLES_HH +#define DUMUX_3P3C_VOLUME_VARIABLES_HH + +#include <dumux/implicit/model.hh> +#include <dumux/material/constants.hh> +#include <dumux/material/fluidstates/compositionalfluidstate.hh> +#include <dumux/material/constraintsolvers/computefromreferencephase.hh> +#include <dumux/material/constraintsolvers/misciblemultiphasecomposition.hh> +#include "properties.hh" + +namespace Dumux +{ + +/*! + * \ingroup ThreePThreeCModel + * \ingroup ImplicitVolumeVariables + * \brief Contains the quantities which are are constant within a + * finite volume in the three-phase three-component model. + */ +template <class TypeTag> +class ThreePThreeCVolumeVariables : public ImplicitVolumeVariables<TypeTag> +{ + typedef ImplicitVolumeVariables<TypeTag> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; + + // constraint solvers + typedef Dumux::MiscibleMultiPhaseComposition<Scalar, FluidSystem> MiscibleMultiPhaseComposition; + typedef Dumux::ComputeFromReferencePhase<Scalar, FluidSystem> ComputeFromReferencePhase; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + dim = GridView::dimension, + + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents), + + wCompIdx = Indices::wCompIdx, + gCompIdx = Indices::gCompIdx, + nCompIdx = Indices::nCompIdx, + + wPhaseIdx = Indices::wPhaseIdx, + gPhaseIdx = Indices::gPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + + switch1Idx = Indices::switch1Idx, + switch2Idx = Indices::switch2Idx, + pressureIdx = Indices::pressureIdx + }; + + // present phases + enum { + threePhases = Indices::threePhases, + wPhaseOnly = Indices::wPhaseOnly, + gnPhaseOnly = Indices::gnPhaseOnly, + wnPhaseOnly = Indices::wnPhaseOnly, + gPhaseOnly = Indices::gPhaseOnly, + wgPhaseOnly = Indices::wgPhaseOnly + }; + + typedef typename GridView::template Codim<0>::Entity Element; + + static const Scalar R; // universial gas constant + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + enum { dofCodim = isBox ? dim : 0 }; + +public: + + typedef typename GET_PROP_TYPE(TypeTag, FluidState) FluidState; + + /*! + * \copydoc ImplicitVolumeVariables::update + */ + void update(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx, + bool isOldSol) + { + ParentType::update(priVars, + problem, + element, + fvGeometry, + scvIdx, + isOldSol); + + bool useConstraintSolver = GET_PROP_VALUE(TypeTag, UseConstraintSolver); + + // capillary pressure parameters + const MaterialLawParams &materialParams = + problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx); + + int dofIdxGlobal = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim); + int phasePresence = problem.model().phasePresence(dofIdxGlobal, isOldSol); + + Scalar temp = Implementation::temperature_(priVars, problem, element, fvGeometry, scvIdx); + fluidState_.setTemperature(temp); + + /* first the saturations */ + if (phasePresence == threePhases) + { + sw_ = priVars[switch1Idx]; + sn_ = priVars[switch2Idx]; + sg_ = 1. - sw_ - sn_; + } + else if (phasePresence == wPhaseOnly) + { + sw_ = 1.; + sn_ = 0.; + sg_ = 0.; + } + else if (phasePresence == gnPhaseOnly) + { + sw_ = 0.; + sn_ = priVars[switch2Idx]; + sg_ = 1. - sn_; + } + else if (phasePresence == wnPhaseOnly) + { + sn_ = priVars[switch2Idx]; + sw_ = 1. - sn_; + sg_ = 0.; + } + else if (phasePresence == gPhaseOnly) + { + sw_ = 0.; + sn_ = 0.; + sg_ = 1.; + } + else if (phasePresence == wgPhaseOnly) + { + sw_ = priVars[switch1Idx]; + sn_ = 0.; + sg_ = 1. - sw_; + } + else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid."); + Valgrind::CheckDefined(sg_); + + fluidState_.setSaturation(wPhaseIdx, sw_); + fluidState_.setSaturation(gPhaseIdx, sg_); + fluidState_.setSaturation(nPhaseIdx, sn_); + + /* now the pressures */ + pg_ = priVars[pressureIdx]; + + // calculate capillary pressures + Scalar pcgw = MaterialLaw::pcgw(materialParams, sw_); + Scalar pcnw = MaterialLaw::pcnw(materialParams, sw_); + Scalar pcgn = MaterialLaw::pcgn(materialParams, sw_ + sn_); + + Scalar pcAlpha = MaterialLaw::pcAlpha(materialParams, sn_); + Scalar pcNW1 = 0.0; // TODO: this should be possible to assign in the problem file + + pn_ = pg_- pcAlpha * pcgn - (1.-pcAlpha)*(pcgw - pcNW1); + pw_ = pn_ - pcAlpha * pcnw - (1.-pcAlpha)*pcNW1; + + fluidState_.setPressure(wPhaseIdx, pw_); + fluidState_.setPressure(gPhaseIdx, pg_); + fluidState_.setPressure(nPhaseIdx, pn_); + + // calculate and set all fugacity coefficients. this is + // possible because we require all phases to be an ideal + // mixture, i.e. fugacity coefficients are not supposed to + // depend on composition! + typename FluidSystem::ParameterCache paramCache; + // assert(FluidSystem::isIdealGas(gPhaseIdx)); + for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { + assert(FluidSystem::isIdealMixture(phaseIdx)); + + for (int compIdx = 0; compIdx < numComponents; ++ compIdx) { + Scalar phi = FluidSystem::fugacityCoefficient(fluidState_, paramCache, phaseIdx, compIdx); + fluidState_.setFugacityCoefficient(phaseIdx, compIdx, phi); + } + } + + // now comes the tricky part: calculate phase composition + if (phasePresence == threePhases) { + // all phases are present, phase compositions are a + // result of the the gas <-> liquid equilibrium. This is + // the job of the "MiscibleMultiPhaseComposition" + // constraint solver ... + if (useConstraintSolver) { + MiscibleMultiPhaseComposition::solve(fluidState_, + paramCache, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + // ... or calculated explicitly this way ... + else { + Scalar partPressH2O = FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx, + wCompIdx) * pw_; + Scalar partPressNAPL = FluidSystem::fugacityCoefficient(fluidState_, + nPhaseIdx, + nCompIdx) * pn_; + Scalar partPressAir = pg_ - partPressH2O - partPressNAPL; + + Scalar xgn = partPressNAPL/pg_; + Scalar xgw = partPressH2O/pg_; + Scalar xgg = partPressAir/pg_; + + // actually, it's nothing else than Henry coefficient + Scalar xwn = partPressNAPL + / (FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,nCompIdx) + * pw_); + Scalar xwg = partPressAir + / (FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,gCompIdx) + * pw_); + Scalar xww = 1.-xwg-xwn; + + Scalar xnn = 1.-2.e-10; + Scalar xna = 1.e-10; + Scalar xnw = 1.e-10; + + fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); + fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); + fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); + fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); + fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); + fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); + fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); + fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); + fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); + + Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); + Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); + Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); + + fluidState_.setDensity(wPhaseIdx, rhoW); + fluidState_.setDensity(gPhaseIdx, rhoG); + fluidState_.setDensity(nPhaseIdx, rhoN); + } + } + else if (phasePresence == wPhaseOnly) { + // only the water phase is present, water phase composition is + // stored explicitly. + + // extract mole fractions in the water phase + Scalar xwg = priVars[switch1Idx]; + Scalar xwn = priVars[switch2Idx]; + Scalar xww = 1 - xwg - xwn; + + // write water mole fractions in the fluid state + fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); + fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); + fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase" constraint solver ... + if (useConstraintSolver) + { + ComputeFromReferencePhase::solve(fluidState_, + paramCache, + wPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + // ... or calculated explicitly this way ... + else { + // note that the gas phase is actually not existing! + // thus, this is used as phase switch criterion + Scalar xgg = xwg * FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,gCompIdx) + * pw_ / pg_; + Scalar xgn = xwn * FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,nCompIdx) + * pw_ / pg_; + Scalar xgw = FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,wCompIdx) + * pw_ / pg_; + + + // note that the gas phase is actually not existing! + // thus, this is used as phase switch criterion + Scalar xnn = xwn * FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,nCompIdx) + * pw_; + Scalar xna = 1.e-10; + Scalar xnw = 1.e-10; + + fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); + fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); + fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); + fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); + fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); + fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); + + Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); + Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); + Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); + + fluidState_.setDensity(wPhaseIdx, rhoW); + fluidState_.setDensity(gPhaseIdx, rhoG); + fluidState_.setDensity(nPhaseIdx, rhoN); + } + } + else if (phasePresence == gnPhaseOnly) { + // only gas and NAPL phases are present + // we have all (partly hypothetical) phase pressures + // and temperature and the mole fraction of water in + // the gas phase + + // we have all (partly hypothetical) phase pressures + // and temperature and the mole fraction of water in + // the gas phase + Scalar partPressNAPL = fluidState_.fugacityCoefficient(nPhaseIdx, nCompIdx)*pn_; + + Scalar xgw = priVars[switch1Idx]; + Scalar xgn = partPressNAPL/pg_; + Scalar xgg = 1.-xgw-xgn; + + // write mole fractions in the fluid state + fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); + fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); + fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase" constraint solver + ComputeFromReferencePhase::solve(fluidState_, + paramCache, + gPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + else if (phasePresence == wnPhaseOnly) { + // only water and NAPL phases are present + Scalar pPartialC = fluidState_.fugacityCoefficient(nPhaseIdx,nCompIdx)*pn_; + Scalar henryC = fluidState_.fugacityCoefficient(wPhaseIdx,nCompIdx)*pw_; + + Scalar xwg = priVars[switch1Idx]; + Scalar xwn = pPartialC/henryC; + Scalar xww = 1.-xwg-xwn; + + // write mole fractions in the fluid state + fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); + fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); + fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase" constraint solver + ComputeFromReferencePhase::solve(fluidState_, + paramCache, + wPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + else if (phasePresence == gPhaseOnly) { + // only the gas phase is present, gas phase composition is + // stored explicitly here below. + + const Scalar xgw = priVars[switch1Idx]; + const Scalar xgn = priVars[switch2Idx]; + Scalar xgg = 1 - xgw - xgn; + + // write mole fractions in the fluid state + fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); + fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); + fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase" constraint solver ... + if (useConstraintSolver) + { + ComputeFromReferencePhase::solve(fluidState_, + paramCache, + gPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + // ... or calculated explicitly this way ... + else { + + // note that the water phase is actually not existing! + // thus, this is used as phase switch criterion + Scalar xww = xgw * pg_ + / (FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,wCompIdx) + * pw_); + Scalar xwn = 1.e-10; + Scalar xwg = 1.e-10; + + // note that the NAPL phase is actually not existing! + // thus, this is used as phase switch criterion + Scalar xnn = xgn * pg_ + / (FluidSystem::fugacityCoefficient(fluidState_, + nPhaseIdx,nCompIdx) + * pn_); + Scalar xna = 1.e-10; + Scalar xnw = 1.e-10; + + fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); + fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); + fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); + fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); + fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); + fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); + + Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); + Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); + Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); + + fluidState_.setDensity(wPhaseIdx, rhoW); + fluidState_.setDensity(gPhaseIdx, rhoG); + fluidState_.setDensity(nPhaseIdx, rhoN); + } + } + else if (phasePresence == wgPhaseOnly) { + // only water and gas phases are present + Scalar xgn = priVars[switch2Idx]; + Scalar partPressH2O = fluidState_.fugacityCoefficient(wPhaseIdx, wCompIdx)*pw_; + + Scalar xgw = partPressH2O/pg_; + Scalar xgg = 1.-xgn-xgw; + + // write mole fractions in the fluid state + fluidState_.setMoleFraction(gPhaseIdx, wCompIdx, xgw); + fluidState_.setMoleFraction(gPhaseIdx, gCompIdx, xgg); + fluidState_.setMoleFraction(gPhaseIdx, nCompIdx, xgn); + + // calculate the composition of the remaining phases (as + // well as the densities of all phases). this is the job + // of the "ComputeFromReferencePhase" constraint solver ... + if (useConstraintSolver) + { + ComputeFromReferencePhase::solve(fluidState_, + paramCache, + gPhaseIdx, + /*setViscosity=*/true, + /*setInternalEnergy=*/false); + } + // ... or calculated explicitly this way ... + else { + // actually, it's nothing else than Henry coefficient + Scalar xwn = xgn * pg_ + / (FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,nCompIdx) + * pw_); + Scalar xwg = xgg * pg_ + / (FluidSystem::fugacityCoefficient(fluidState_, + wPhaseIdx,gCompIdx) + * pw_); + Scalar xww = 1.-xwg-xwn; + + // note that the NAPL phase is actually not existing! + // thus, this is used as phase switch criterion + Scalar xnn = xgn * pg_ + / (FluidSystem::fugacityCoefficient(fluidState_, + nPhaseIdx,nCompIdx) + * pn_); + Scalar xna = 1.e-10; + Scalar xnw = 1.e-10; + + fluidState_.setMoleFraction(wPhaseIdx, wCompIdx, xww); + fluidState_.setMoleFraction(wPhaseIdx, gCompIdx, xwg); + fluidState_.setMoleFraction(wPhaseIdx, nCompIdx, xwn); + fluidState_.setMoleFraction(nPhaseIdx, wCompIdx, xnw); + fluidState_.setMoleFraction(nPhaseIdx, gCompIdx, xna); + fluidState_.setMoleFraction(nPhaseIdx, nCompIdx, xnn); + + Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx); + Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx); + Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx); + + fluidState_.setDensity(wPhaseIdx, rhoW); + fluidState_.setDensity(gPhaseIdx, rhoG); + fluidState_.setDensity(nPhaseIdx, rhoN); + } + } + else + assert(false); // unhandled phase state + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + // Mobilities + const Scalar mu = + FluidSystem::viscosity(fluidState_, + paramCache, + phaseIdx); + fluidState_.setViscosity(phaseIdx,mu); + + Scalar kr; + kr = MaterialLaw::kr(materialParams, phaseIdx, + fluidState_.saturation(wPhaseIdx), + fluidState_.saturation(nPhaseIdx), + fluidState_.saturation(gPhaseIdx)); + mobility_[phaseIdx] = kr / mu; + Valgrind::CheckDefined(mobility_[phaseIdx]); + } + + // material dependent parameters for NAPL adsorption + bulkDensTimesAdsorpCoeff_ = + MaterialLaw::bulkDensTimesAdsorpCoeff(materialParams); + + /* ATTENTION: The conversion to effective diffusion parameters + * for the porous media happens at another place! + */ + + // diffusivity coefficents + diffusionCoefficient_[gPhaseIdx][wCompIdx] = + FluidSystem::diffusionCoefficient(fluidState_, + paramCache, + gPhaseIdx, + wCompIdx); + diffusionCoefficient_[gPhaseIdx][nCompIdx] = + FluidSystem::diffusionCoefficient(fluidState_, + paramCache, + gPhaseIdx, + nCompIdx); + diffusionCoefficient_[gPhaseIdx][gCompIdx] = 0.0; // dummy, should not be used ! + + diffusionCoefficient_[wPhaseIdx][gCompIdx] = + FluidSystem::diffusionCoefficient(fluidState_, + paramCache, + wPhaseIdx, + gCompIdx); + diffusionCoefficient_[wPhaseIdx][nCompIdx] = + FluidSystem::diffusionCoefficient(fluidState_, + paramCache, + wPhaseIdx, + nCompIdx); + diffusionCoefficient_[wPhaseIdx][wCompIdx] = 0.0; // dummy, should not be used ! + + /* no diffusion in NAPL phase considered at the moment */ + diffusionCoefficient_[nPhaseIdx][nCompIdx] = 0.0; + diffusionCoefficient_[nPhaseIdx][wCompIdx] = 0.0; + diffusionCoefficient_[nPhaseIdx][gCompIdx] = 0.0; + + Valgrind::CheckDefined(diffusionCoefficient_); + + // porosity + porosity_ = problem.spatialParams().porosity(element, + fvGeometry, + scvIdx); + Valgrind::CheckDefined(porosity_); + + // energy related quantities not contained in the fluid state + asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol); + // compute and set the enthalpy + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + Scalar h = Implementation::enthalpy_(fluidState_, paramCache, phaseIdx); + fluidState_.setEnthalpy(phaseIdx, h); + } + } + + /*! + * \brief Returns the phase state for the control volume. + */ + const FluidState &fluidState() const + { return fluidState_; } + + /*! + * \brief Returns the effective saturation of a given phase within + * the control volume. + * + * \param phaseIdx The phase index + */ + Scalar saturation(const int phaseIdx) const + { return fluidState_.saturation(phaseIdx); } + + /*! + * \brief Returns the mass fraction of a given component in a + * given phase within the control volume in \f$[-]\f$. + * + * \param phaseIdx The phase index + * \param compIdx The component index + */ + Scalar massFraction(const int phaseIdx, const int compIdx) const + { return fluidState_.massFraction(phaseIdx, compIdx); } + + /*! + * \brief Returns the mole fraction of a given component in a + * given phase within the control volume in \f$[-]\f$. + * + * \param phaseIdx The phase index + * \param compIdx The component index + */ + Scalar moleFraction(const int phaseIdx, const int compIdx) const + { return fluidState_.moleFraction(phaseIdx, compIdx); } + + /*! + * \brief Returns the mass density of a given phase within the + * control volume. + * + * \param phaseIdx The phase index + */ + Scalar density(const int phaseIdx) const + { return fluidState_.density(phaseIdx); } + + /*! + * \brief Returns the molar density of a given phase within the + * control volume. + * + * \param phaseIdx The phase index + */ + Scalar molarDensity(const int phaseIdx) const + { return fluidState_.density(phaseIdx) / fluidState_.averageMolarMass(phaseIdx); } + + /*! + * \brief Returns the effective pressure of a given phase within + * the control volume. + * + * \param phaseIdx The phase index + */ + Scalar pressure(const int phaseIdx) const + { return fluidState_.pressure(phaseIdx); } + + /*! + * \brief Returns temperature inside the sub-control volume. + * + * Note that we assume thermodynamic equilibrium, i.e. the + * temperatures of the rock matrix and of all fluid phases are + * identical. + */ + Scalar temperature() const + { return fluidState_.temperature(/*phaseIdx=*/0); } + + /*! + * \brief Returns the effective mobility of a given phase within + * the control volume. + * + * \param phaseIdx The phase index + */ + Scalar mobility(const int phaseIdx) const + { + return mobility_[phaseIdx]; + } + + /*! + * \brief Returns the effective capillary pressure within the control volume. + */ + Scalar capillaryPressure() const + { return fluidState_.capillaryPressure(); } + + /*! + * \brief Returns the average porosity within the control volume. + */ + Scalar porosity() const + { return porosity_; } + + /*! + * \brief Returns the diffusivity coefficient matrix. + */ + Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficient() const + { return diffusionCoefficient_; } + + /*! + * \brief Returns the adsorption information. + */ + Scalar bulkDensTimesAdsorpCoeff() const + { return bulkDensTimesAdsorpCoeff_; } + + +protected: + + static Scalar temperature_(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) + { + return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global); + } + + /*! + * \brief Called by update() to compute the energy related quantities + */ + void updateEnergy_(const PrimaryVariables &priVars, + const Problem &problem, + const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx, + bool isOldSol) + { } + + template<class ParameterCache> + static Scalar enthalpy_(const FluidState& fluidState, + const ParameterCache& paramCache, + const int phaseIdx) + { + return 0; + } + + Scalar sw_, sg_, sn_, pg_, pw_, pn_; + + Scalar moleFrac_[numPhases][numComponents]; + Scalar massFrac_[numPhases][numComponents]; + + Scalar porosity_; //!< Effective porosity within the control volume + Scalar mobility_[numPhases]; //!< Effective mobility within the control volume + Scalar bulkDensTimesAdsorpCoeff_; //!< the basis for calculating adsorbed NAPL + /* We need a tensor here !! */ + //!< Binary diffusion coefficients of the 3 components in the phases + Dune::FieldMatrix<Scalar, numPhases, numComponents> diffusionCoefficient_; + FluidState fluidState_; + +private: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } +}; + +template <class TypeTag> +const typename ThreePThreeCVolumeVariables<TypeTag>::Scalar ThreePThreeCVolumeVariables<TypeTag>::R + = Constants<typename GET_PROP_TYPE(TypeTag, Scalar)>::R; + +} // end namespace + +#endif diff --git a/test/material/fluidmatrixinteractions/2p/thermalconductivityjohansenproblem.hh b/test/material/fluidmatrixinteractions/2p/thermalconductivityjohansenproblem.hh index bf4a1ced20..dd84bc4751 100644 --- a/test/material/fluidmatrixinteractions/2p/thermalconductivityjohansenproblem.hh +++ b/test/material/fluidmatrixinteractions/2p/thermalconductivityjohansenproblem.hh @@ -28,7 +28,7 @@ #include <dumux/material/fluidsystems/h2on2fluidsystem.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidmatrixinteractions/2p/thermalconductivityjohansen.hh> diff --git a/test/material/fluidmatrixinteractions/2p/thermalconductivitysomertonproblem.hh b/test/material/fluidmatrixinteractions/2p/thermalconductivitysomertonproblem.hh index 965ac84f8a..48d65dbdd9 100644 --- a/test/material/fluidmatrixinteractions/2p/thermalconductivitysomertonproblem.hh +++ b/test/material/fluidmatrixinteractions/2p/thermalconductivitysomertonproblem.hh @@ -28,7 +28,7 @@ #include <dumux/material/fluidsystems/h2on2fluidsystem.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidmatrixinteractions/2p/thermalconductivitysomerton.hh> diff --git a/test/material/fluidmatrixinteractions/2p/thermalconductivityspatialparams.hh b/test/material/fluidmatrixinteractions/2p/thermalconductivityspatialparams.hh index 6d193a258e..c33dc54687 100644 --- a/test/material/fluidmatrixinteractions/2p/thermalconductivityspatialparams.hh +++ b/test/material/fluidmatrixinteractions/2p/thermalconductivityspatialparams.hh @@ -29,7 +29,7 @@ #include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh> #include <dumux/material/fluidmatrixinteractions/2p/efftoabslaw.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> namespace Dumux { diff --git a/test/material/fluidmatrixinteractions/effectivediffusivityconstanttauproblem.hh b/test/material/fluidmatrixinteractions/effectivediffusivityconstanttauproblem.hh index 5bc8aa394a..64e0963b96 100644 --- a/test/material/fluidmatrixinteractions/effectivediffusivityconstanttauproblem.hh +++ b/test/material/fluidmatrixinteractions/effectivediffusivityconstanttauproblem.hh @@ -28,7 +28,7 @@ #include <dumux/material/fluidsystems/h2on2fluidsystem.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidmatrixinteractions/diffusivityconstanttau.hh> diff --git a/test/material/fluidmatrixinteractions/effectivediffusivitymillingtonquirkproblem.hh b/test/material/fluidmatrixinteractions/effectivediffusivitymillingtonquirkproblem.hh index 40dcb8d30a..1cb0d2d979 100644 --- a/test/material/fluidmatrixinteractions/effectivediffusivitymillingtonquirkproblem.hh +++ b/test/material/fluidmatrixinteractions/effectivediffusivitymillingtonquirkproblem.hh @@ -28,7 +28,7 @@ #include <dumux/material/fluidsystems/h2on2fluidsystem.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh> diff --git a/test/material/fluidmatrixinteractions/effectivediffusivityspatialparams.hh b/test/material/fluidmatrixinteractions/effectivediffusivityspatialparams.hh index e778697e64..eebfbfa931 100644 --- a/test/material/fluidmatrixinteractions/effectivediffusivityspatialparams.hh +++ b/test/material/fluidmatrixinteractions/effectivediffusivityspatialparams.hh @@ -29,7 +29,7 @@ #include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh> #include <dumux/material/fluidmatrixinteractions/2p/efftoabslaw.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> namespace Dumux { diff --git a/test/multidomain/2cnistokes2p2cni/2p2cnisubproblem.hh b/test/multidomain/2cnistokes2p2cni/2p2cnisubproblem.hh index 23d36df3ac..20688c0c7b 100644 --- a/test/multidomain/2cnistokes2p2cni/2p2cnisubproblem.hh +++ b/test/multidomain/2cnistokes2p2cni/2p2cnisubproblem.hh @@ -27,7 +27,7 @@ #include <dune/common/float_cmp.hh> #include <dumux/porousmediumflow/implicit/problem.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #include <dumux/io/gnuplotinterface.hh> #include <dumux/multidomain/2cnistokes2p2cni/2p2cnicouplinglocalresidual.hh> #include <dumux/multidomain/common/subdomainpropertydefaults.hh> diff --git a/test/multidomain/2cnizeroeq2p2cni/2p2cnisubproblem.hh b/test/multidomain/2cnizeroeq2p2cni/2p2cnisubproblem.hh index 5866f3a692..45504fe96b 100644 --- a/test/multidomain/2cnizeroeq2p2cni/2p2cnisubproblem.hh +++ b/test/multidomain/2cnizeroeq2p2cni/2p2cnisubproblem.hh @@ -24,7 +24,7 @@ #ifndef DUMUX_2P2CNISUB_PROBLEM_HH #define DUMUX_2P2CNISUB_PROBLEM_HH -#include <dumux/implicit/2p2c/2p2cindices.hh> +#include <dumux/porousmediumflow/2p2c/implicit/indices.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidmatrixinteractions/2p/thermalconductivityjohansen.hh> #include <dumux/material/fluidmatrixinteractions/2p/thermalconductivitysomerton.hh> diff --git a/test/multidomain/2cstokes2p2c/2p2csubproblem.hh b/test/multidomain/2cstokes2p2c/2p2csubproblem.hh index d1eb5f75b8..edfb76caf2 100644 --- a/test/multidomain/2cstokes2p2c/2p2csubproblem.hh +++ b/test/multidomain/2cstokes2p2c/2p2csubproblem.hh @@ -26,7 +26,7 @@ #include <dune/common/float_cmp.hh> -#include <dumux/implicit/2p2c/2p2cindices.hh> +#include <dumux/porousmediumflow/2p2c/implicit/indices.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/multidomain/2cstokes2p2c/2p2ccouplinglocalresidual.hh> #include <dumux/multidomain/common/subdomainpropertydefaults.hh> diff --git a/test/multidomain/2czeroeq2p2c/2p2csubproblem.hh b/test/multidomain/2czeroeq2p2c/2p2csubproblem.hh index 706e50daa6..f7a26669f0 100644 --- a/test/multidomain/2czeroeq2p2c/2p2csubproblem.hh +++ b/test/multidomain/2czeroeq2p2c/2p2csubproblem.hh @@ -25,7 +25,7 @@ #ifndef DUMUX_TWOPTWOC_SUBPROBLEM_HH #define DUMUX_TWOPTWOC_SUBPROBLEM_HH -#include <dumux/implicit/2p2c/2p2cindices.hh> +#include <dumux/porousmediumflow/2p2c/implicit/indices.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/multidomain/common/subdomainpropertydefaults.hh> #include <dumux/multidomain/common/multidomainlocaloperator.hh> diff --git a/test/porousmediumflow/1p2c/implicit/1p2cniconductionproblem.hh b/test/porousmediumflow/1p2c/implicit/1p2cniconductionproblem.hh index 30fe8390ae..533e9a3789 100644 --- a/test/porousmediumflow/1p2c/implicit/1p2cniconductionproblem.hh +++ b/test/porousmediumflow/1p2c/implicit/1p2cniconductionproblem.hh @@ -27,7 +27,7 @@ #include <dune/grid/io/file/dgfparser/dgfyasp.hh> -#include <dumux/implicit/1p2c/1p2cmodel.hh> +#include <dumux/porousmediumflow/1p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidsystems/h2on2liquidphasefluidsystem.hh> diff --git a/test/porousmediumflow/1p2c/implicit/1p2cniconvectionproblem.hh b/test/porousmediumflow/1p2c/implicit/1p2cniconvectionproblem.hh index 33c23231f3..df86cd7e4c 100644 --- a/test/porousmediumflow/1p2c/implicit/1p2cniconvectionproblem.hh +++ b/test/porousmediumflow/1p2c/implicit/1p2cniconvectionproblem.hh @@ -28,7 +28,7 @@ #include <dune/grid/io/file/dgfparser/dgfyasp.hh> -#include <dumux/implicit/1p2c/1p2cmodel.hh> +#include <dumux/porousmediumflow/1p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/components/h2o.hh> #include <dumux/material/fluidsystems/h2on2liquidphasefluidsystem.hh> diff --git a/test/porousmediumflow/1p2c/implicit/1p2coutflowproblem.hh b/test/porousmediumflow/1p2c/implicit/1p2coutflowproblem.hh index 86479bb40d..7e1f814c1d 100644 --- a/test/porousmediumflow/1p2c/implicit/1p2coutflowproblem.hh +++ b/test/porousmediumflow/1p2c/implicit/1p2coutflowproblem.hh @@ -29,7 +29,7 @@ #endif #include <dune/grid/io/file/dgfparser/dgfyasp.hh> -#include <dumux/implicit/1p2c/1p2cmodel.hh> +#include <dumux/porousmediumflow/1p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidsystems/h2on2liquidphasefluidsystem.hh> diff --git a/test/porousmediumflow/2p2c/implicit/injectionproblem.hh b/test/porousmediumflow/2p2c/implicit/injectionproblem.hh index 6a4c19181c..eea1ceaeff 100644 --- a/test/porousmediumflow/2p2c/implicit/injectionproblem.hh +++ b/test/porousmediumflow/2p2c/implicit/injectionproblem.hh @@ -26,7 +26,7 @@ #include <dune/grid/io/file/dgfparser/dgfyasp.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidsystems/h2on2fluidsystem.hh> diff --git a/test/porousmediumflow/2p2c/implicit/injectionspatialparams.hh b/test/porousmediumflow/2p2c/implicit/injectionspatialparams.hh index 029140c28e..3b9181bf70 100644 --- a/test/porousmediumflow/2p2c/implicit/injectionspatialparams.hh +++ b/test/porousmediumflow/2p2c/implicit/injectionspatialparams.hh @@ -31,7 +31,7 @@ #include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh> #include <dumux/material/fluidmatrixinteractions/2p/efftoabslaw.hh> -#include <dumux/implicit/2p2c/2p2cproperties.hh> +#include <dumux/porousmediumflow/2p2c/implicit/properties.hh> namespace Dumux { diff --git a/test/porousmediumflow/2p2c/implicit/waterairproblem.hh b/test/porousmediumflow/2p2c/implicit/waterairproblem.hh index fd01cefbc8..ba6b25f33e 100644 --- a/test/porousmediumflow/2p2c/implicit/waterairproblem.hh +++ b/test/porousmediumflow/2p2c/implicit/waterairproblem.hh @@ -29,7 +29,7 @@ #include <dumux/material/fluidsystems/h2on2fluidsystem.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include "waterairspatialparams.hh" diff --git a/test/porousmediumflow/2p2c/implicit/waterairspatialparams.hh b/test/porousmediumflow/2p2c/implicit/waterairspatialparams.hh index b3b071d942..a8f534877e 100644 --- a/test/porousmediumflow/2p2c/implicit/waterairspatialparams.hh +++ b/test/porousmediumflow/2p2c/implicit/waterairspatialparams.hh @@ -31,7 +31,7 @@ #include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh> #include <dumux/material/fluidmatrixinteractions/2p/efftoabslaw.hh> -#include <dumux/implicit/2p2c/2p2cmodel.hh> +#include <dumux/porousmediumflow/2p2c/implicit/model.hh> namespace Dumux { diff --git a/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh b/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh index 19d547f1ab..fe77d0fd46 100644 --- a/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh +++ b/test/porousmediumflow/2pnc/implicit/fuelcellproblem.hh @@ -25,7 +25,7 @@ #define DUMUX_FUELCELL_PROBLEM_HH #include <dumux/io/cubegridcreator.hh> -#include <dumux/implicit/2pnc/2pncmodel.hh> +#include <dumux/porousmediumflow/2pnc/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include <dumux/material/fluidsystems/h2on2o2fluidsystem.hh> #include <dumux/material/constants.hh> diff --git a/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh b/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh index 9ee7aed63e..a194f5667b 100644 --- a/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh +++ b/test/porousmediumflow/2pnc/implicit/fuelcellspatialparams.hh @@ -31,7 +31,7 @@ #include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh> #include <dumux/material/fluidmatrixinteractions/2p/regularizedvangenuchten.hh> #include <dumux/material/fluidmatrixinteractions/2p/philtophoblaw.hh> -#include <dumux/implicit/2pnc/2pncmodel.hh> +#include <dumux/porousmediumflow/2pnc/implicit/model.hh> namespace Dumux { diff --git a/test/porousmediumflow/2pncmin/implicit/dissolutionproblem.hh b/test/porousmediumflow/2pncmin/implicit/dissolutionproblem.hh index 73644c5552..6027ac1a96 100644 --- a/test/porousmediumflow/2pncmin/implicit/dissolutionproblem.hh +++ b/test/porousmediumflow/2pncmin/implicit/dissolutionproblem.hh @@ -24,7 +24,7 @@ #ifndef DUMUX_DISSOLUTION_PROBLEM_HH #define DUMUX_DISSOLUTION_PROBLEM_HH -#include <dumux/implicit/2pncmin/2pncminmodel.hh> +#include <dumux/porousmediumflow/2pncmin/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include<dumux/material/fluidsystems/brineairfluidsystem.hh> diff --git a/test/porousmediumflow/2pncmin/implicit/dissolutionspatialparams.hh b/test/porousmediumflow/2pncmin/implicit/dissolutionspatialparams.hh index dc40d8de56..6a79121406 100644 --- a/test/porousmediumflow/2pncmin/implicit/dissolutionspatialparams.hh +++ b/test/porousmediumflow/2pncmin/implicit/dissolutionspatialparams.hh @@ -19,7 +19,7 @@ #ifndef DUMUX_INJECTION_SPATIAL_PARAMETERS_HH #define DUMUX_INJECTION_SPATIAL_PARAMETERS_HH -#include <dumux/implicit/2pncmin/2pncminindices.hh> +#include <dumux/porousmediumflow/2pncmin/implicit/indices.hh> #include <dumux/material/spatialparams/implicitspatialparams.hh> #include <dumux/material/fluidmatrixinteractions/2p/linearmaterial.hh> #include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh> diff --git a/test/porousmediumflow/3p/implicit/3pnispatialparams.hh b/test/porousmediumflow/3p/implicit/3pnispatialparams.hh index 441231520f..a83292de10 100644 --- a/test/porousmediumflow/3p/implicit/3pnispatialparams.hh +++ b/test/porousmediumflow/3p/implicit/3pnispatialparams.hh @@ -24,7 +24,7 @@ #ifndef DUMUX_THREEPNI_SPATIAL_PARAMS_HH #define DUMUX_THREEPNI_SPATIAL_PARAMS_HH -#include <dumux/implicit/3p3c/3p3cindices.hh> +#include <dumux/porousmediumflow/3p3c/implicit/indices.hh> #include <dumux/material/spatialparams/implicitspatialparams.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3p.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3pparams.hh> diff --git a/test/porousmediumflow/3p/implicit/infiltration3pspatialparams.hh b/test/porousmediumflow/3p/implicit/infiltration3pspatialparams.hh index bcf6547a55..92db70a4d6 100644 --- a/test/porousmediumflow/3p/implicit/infiltration3pspatialparams.hh +++ b/test/porousmediumflow/3p/implicit/infiltration3pspatialparams.hh @@ -25,7 +25,7 @@ #ifndef DUMUX_INFILTRATION_THREEP_SPATIAL_PARAMS_HH #define DUMUX_INFILTRATION_THREEP_SPATIAL_PARAMS_HH -#include <dumux/implicit/3p3c/3p3cindices.hh> +#include <dumux/porousmediumflow/3p3c/implicit/indices.hh> #include <dumux/material/spatialparams/implicitspatialparams.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3p.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3pparams.hh> diff --git a/test/porousmediumflow/3p3c/implicit/columnxylolproblem.hh b/test/porousmediumflow/3p3c/implicit/columnxylolproblem.hh index 2f10cd732d..28b2566923 100644 --- a/test/porousmediumflow/3p3c/implicit/columnxylolproblem.hh +++ b/test/porousmediumflow/3p3c/implicit/columnxylolproblem.hh @@ -29,7 +29,7 @@ #include <dumux/material/fluidsystems/h2oairxylenefluidsystem.hh> -#include <dumux/implicit/3p3c/3p3cmodel.hh> +#include <dumux/porousmediumflow/3p3c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include "columnxylolspatialparams.hh" diff --git a/test/porousmediumflow/3p3c/implicit/columnxylolspatialparams.hh b/test/porousmediumflow/3p3c/implicit/columnxylolspatialparams.hh index 436f3a033d..c4bd4ac7c3 100644 --- a/test/porousmediumflow/3p3c/implicit/columnxylolspatialparams.hh +++ b/test/porousmediumflow/3p3c/implicit/columnxylolspatialparams.hh @@ -24,7 +24,7 @@ #ifndef DUMUX_COLUMNXYLOL_SPATIAL_PARAMS_HH #define DUMUX_COLUMNXYLOL_SPATIAL_PARAMS_HH -#include <dumux/implicit/3p3c/3p3cindices.hh> +#include <dumux/porousmediumflow/3p3c/implicit/indices.hh> #include <dumux/material/spatialparams/implicitspatialparams.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3p.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3pparams.hh> diff --git a/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh b/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh index 8eaf28c0ed..5a3129a3ec 100644 --- a/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh +++ b/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh @@ -29,7 +29,7 @@ #include <dumux/material/fluidsystems/h2oairmesitylenefluidsystem.hh> -#include <dumux/implicit/3p3c/3p3cmodel.hh> +#include <dumux/porousmediumflow/3p3c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include "infiltrationspatialparameters.hh" diff --git a/test/porousmediumflow/3p3c/implicit/infiltrationspatialparameters.hh b/test/porousmediumflow/3p3c/implicit/infiltrationspatialparameters.hh index e5b22b8677..024e32bffd 100644 --- a/test/porousmediumflow/3p3c/implicit/infiltrationspatialparameters.hh +++ b/test/porousmediumflow/3p3c/implicit/infiltrationspatialparameters.hh @@ -26,7 +26,7 @@ #ifndef DUMUX_INFILTRATION_SPATIAL_PARAMETERS_HH #define DUMUX_INFILTRATION_SPATIAL_PARAMETERS_HH -#include <dumux/implicit/3p3c/3p3cindices.hh> +#include <dumux/porousmediumflow/3p3c/implicit/indices.hh> #include <dumux/material/spatialparams/implicitspatialparams.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3p.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3pparams.hh> diff --git a/test/porousmediumflow/3p3c/implicit/kuevetteproblem.hh b/test/porousmediumflow/3p3c/implicit/kuevetteproblem.hh index 0b5dba8358..2f07ac940f 100644 --- a/test/porousmediumflow/3p3c/implicit/kuevetteproblem.hh +++ b/test/porousmediumflow/3p3c/implicit/kuevetteproblem.hh @@ -31,7 +31,7 @@ #include <dumux/material/fluidsystems/h2oairmesitylenefluidsystem.hh> -#include <dumux/implicit/3p3c/3p3cmodel.hh> +#include <dumux/porousmediumflow/3p3c/implicit/model.hh> #include <dumux/porousmediumflow/implicit/problem.hh> #include "kuevettespatialparams.hh" diff --git a/test/porousmediumflow/3p3c/implicit/kuevettespatialparams.hh b/test/porousmediumflow/3p3c/implicit/kuevettespatialparams.hh index 1bd6bbec7f..39f1e2fc1d 100644 --- a/test/porousmediumflow/3p3c/implicit/kuevettespatialparams.hh +++ b/test/porousmediumflow/3p3c/implicit/kuevettespatialparams.hh @@ -26,7 +26,7 @@ #include <dune/common/float_cmp.hh> -#include <dumux/implicit/3p3c/3p3cindices.hh> +#include <dumux/porousmediumflow/3p3c/implicit/indices.hh> #include <dumux/material/spatialparams/implicitspatialparams.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3p.hh> #include <dumux/material/fluidmatrixinteractions/3p/regularizedparkervangen3pparams.hh> -- GitLab