From c6404ab859c380b2f1f1c647d9bc0628ae2e6e90 Mon Sep 17 00:00:00 2001 From: Markus Wolff <markus.wolff@twt-gmbh.de> Date: Mon, 9 Sep 2013 13:33:30 +0000 Subject: [PATCH] Added new grid adaptation indicator for 2p models git-svn-id: svn://svn.iws.uni-stuttgart.de/DUMUX/dumux/trunk@11426 2fb0f335-1f38-0410-981e-8018bf24f1b0 --- .../impes/gridadaptionindicator2plocalflux.hh | 646 ++++++++++++++++++ 1 file changed, 646 insertions(+) create mode 100644 dumux/decoupled/2p/impes/gridadaptionindicator2plocalflux.hh diff --git a/dumux/decoupled/2p/impes/gridadaptionindicator2plocalflux.hh b/dumux/decoupled/2p/impes/gridadaptionindicator2plocalflux.hh new file mode 100644 index 0000000000..a3f34f501a --- /dev/null +++ b/dumux/decoupled/2p/impes/gridadaptionindicator2plocalflux.hh @@ -0,0 +1,646 @@ +// -*- 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_GRIDADAPTIONINDICATOR2PLOCALFLUX_HH +#define DUMUX_GRIDADAPTIONINDICATOR2PLOCALFLUX_HH + +#include <dumux/decoupled/common/impetproperties.hh> +#include <dumux/decoupled/2p/2pproperties.hh> + +/** + * @file + * @brief Class defining a standard, saturation dependent indicator for grid adaption + */ +namespace Dumux +{ + +namespace Properties +{ +NEW_PROP_TAG(GridAdaptRefineThresholdFlux); +NEW_PROP_TAG(GridAdaptCoarsenThresholdFlux); +NEW_PROP_TAG(GridAdaptRefineThresholdSat); +NEW_PROP_TAG(GridAdaptCoarsenThresholdSat); +NEW_PROP_TAG(GridAdaptRefinePercentileFlux); +NEW_PROP_TAG(GridAdaptCoarsenPercentileFlux); +NEW_PROP_TAG(GridAdaptRefinePercentileSat); +NEW_PROP_TAG(GridAdaptCoarsenPercentileSat); + +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptRefineThresholdFlux, 0.8); +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptCoarsenThresholdFlux, 0.2); +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptRefineThresholdSat, 0.8); +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptCoarsenThresholdSat, 0.2); +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptRefinePercentileFlux, 0.8); +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptCoarsenPercentileFlux, 0.2); +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptRefinePercentileSat, 0.8); +SET_SCALAR_PROP(GridAdaptTypeTag, GridAdaptCoarsenPercentileSat, 0.2); + +} + +/*!\ingroup IMPES + * @brief Class defining a standard, saturation dependent indicator for grid adaption + * + * \tparam TypeTag The problem TypeTag + */ +template<class TypeTag> +class GridAdaptionIndicator2PLocalFlux +{ +private: + 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 GridView::IntersectionIterator IntersectionIterator; + typedef typename GridView::Traits::template Codim<0>::Entity Element; + typedef typename GridView::Traits::template Codim<0>::EntityPointer ElementPointer; + typedef typename GridView::template Codim<0>::Iterator ElementIterator; + + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename Grid::LevelGridView::IndexSet IndexSet; + + typedef typename GET_PROP(TypeTag, SolutionTypes) SolutionTypes; + typedef typename SolutionTypes::ScalarSolution ScalarSolutionType; + + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, CellData) CellData; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + + enum + { + dim = GridView::dimension, dimWorld = GridView::dimensionworld + }; + + enum + { + Sw = Indices::saturationW, + Sn = Indices::saturationNW, + eqIdxSat = Indices::satEqIdx + }; + enum + { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + numPhases = GET_PROP_VALUE(TypeTag, NumPhases) + }; + + typedef Dune::GenericReferenceElements<Scalar, dim> ReferenceElementContainer; + typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef Dune::FieldVector<Scalar, dim> DimVector; + typedef Dune::FieldMatrix<Scalar, dim, dim> DimMatrix; + typedef Dune::FieldVector<Scalar,2> SetVector; + + struct SetField { + Scalar indicator; + Scalar volume; + int index; + SetField() + :indicator(0),volume(0), index(0) + {} + }; + + struct Comparison { + bool operator() (const SetField& lhs, const SetField& rhs) const + {return lhs.indicator<rhs.indicator;} + }; + + typedef std::set<SetField, Comparison> RangeSet; + +public: + /*! \brief Calculates the indicator used for refinement/coarsening for each grid cell. + * + * This standard indicator is based on the saturation gradient. + */ + void calculateIndicator() + { + + int size = problem_.variables().cellDataGlobal().size(); + + // prepare an indicator for refinement + indicatorVector_.resize(size); + + if (useSatInd_ || usePercentileSat_) + indicatorVectorSat_.resize(size); + if (useFluxInd_ || usePercentileFlux_) + indicatorVectorFlux_.resize(size); + + + RangeSet satRange; + RangeSet fluxRange; + + SetField satVec; + SetField fluxVec; + + Scalar totalVolume = 0; + Scalar totalVolumeSat = 0; + + ElementIterator eItEnd = problem_.gridView().template end<0>(); + // 1) calculate Indicator -> min, maxvalues + // Schleife über alle Leaf-Elemente + for (ElementIterator eIt = problem_.gridView().template begin<0>(); eIt != eItEnd; + ++eIt) + { + // Bestimme maximale und minimale Sättigung + // Index des aktuellen Leaf-Elements + int globalIdxI = problem_.variables().index(*eIt); + + indicatorVector_[globalIdxI] = 0.5 * (refineBound_ + coarsenBound_); + if (useSatInd_ || usePercentileSat_) + indicatorVectorSat_[globalIdxI] = -1e100; + if (useFluxInd_ || usePercentileFlux_) + indicatorVectorFlux_[globalIdxI] = -1e100; + + const CellData& cellDataI = problem_.variables().cellData(globalIdxI); + + bool isSpecialCell = false; + + if (!checkPhysicalRange_(cellDataI)) + { + indicatorVector_[globalIdxI] = refineBound_ + 1.0; + isSpecialCell = true; + } + + Scalar volume = eIt->geometry().volume(); + totalVolume += volume; + + if (refineAtSource_) + { + PrimaryVariables source(0.0); + problem_.sourceAtPos(source, eIt->geometry().center()); + for (int i = 0; i < 2; i++) + { + if (std::abs(source[i]) > 1e-10) + { + indicatorVector_[globalIdxI] = refineBound_ + 1.0; + isSpecialCell = true; + break; + } + } + } + + if (isSpecialCell) + { + continue; + } + + Scalar satI = 0.0; + Scalar satW = 0.0; + switch (saturationType_) + { + case Sw: + satI = cellDataI.saturation(wPhaseIdx); + satW = satI; + break; + case Sn: + satI = cellDataI.saturation(nPhaseIdx); + satW = 1.0-satI; + break; + } + + Dune::FieldVector < Scalar, 2 * dim > flux(0); + // Berechne Verfeinerungsindikator an allen Zellen + IntersectionIterator isItend = problem_.gridView().iend(*eIt); + for (IntersectionIterator isIt = problem_.gridView().ibegin(*eIt); isIt != isItend; ++isIt) + { + if (isSpecialCell) + { + break; + } + + if (isIt->neighbor()) + { + const CellData& cellDataJ = problem_.variables().cellData(problem_.variables().index(*(isIt->outside()))); + if (!checkPhysicalRange_(cellDataJ)) + { + indicatorVector_[globalIdxI] = refineBound_ + 1.0; + isSpecialCell = true; + break; + } + } + + int idxInInside = isIt->indexInInside(); + + if (useFluxInd_ || usePercentileFlux_) + { + int isIndex = isIt->indexInInside(); + flux[isIndex] += (isIt->centerUnitOuterNormal() * cellDataI.fluxData().velocityTotal(idxInInside)) * isIt->geometry().volume(); + + // Scalar velNorm = cellDataI.fluxData().velocityTotal(idxInInside).two_norm(); + // indicatorVectorFlux_[globalIdxI] = std::max(velNorm, indicatorVectorFlux_[globalIdxI]); + } + + const typename IntersectionIterator::Intersection &intersection = *isIt; + // Steige aus, falls es sich nicht um einen Nachbarn handelt + if (isIt->boundary()) + { + BoundaryTypes bcTypes; + problem_.boundaryTypes(bcTypes, *isIt); + + for (int i = 0; i < 2; i++) + { + if (bcTypes.isNeumann(i)) + { + PrimaryVariables flux(0.0); + problem_.neumann(flux, *isIt); + + bool fluxBound = false; + for (int j = 0; j < 2; j++) + { + if (std::abs(flux[j]) > 1e-10) + { + if (refineAtFluxBC_) + { + indicatorVector_[globalIdxI] = refineBound_ + 1.0; + isSpecialCell = true; + fluxBound = true; + break; + } + } + } + if (fluxBound) + break; + } + else if (bcTypes.isDirichlet(i)) + { + if (refineAtDirichletBC_) + { + indicatorVector_[globalIdxI] = refineBound_ + 1.0; + isSpecialCell = true; + break; + } + } + } + if (useSatInd_ || usePercentileSat_) + { + Scalar satJ = satI; + if (bcTypes.isDirichlet(eqIdxSat)) + { + PrimaryVariables sat(0.0); + problem_.dirichlet(sat, *isIt); + satJ = sat[eqIdxSat]; + } + Scalar localdelta = std::abs(satI - satJ); + indicatorVectorSat_[globalIdxI] = std::max(indicatorVectorSat_[globalIdxI], localdelta); + } + } + else + { + if (useSatInd_ || usePercentileSat_) + { + // Greife auf Nachbarn zu + ElementPointer outside = intersection.outside(); + int globalIdxJ = problem_.variables().index(*outside); + + Scalar satJ = 0.; + switch (saturationType_) + { + case Sw: + satJ = problem_.variables().cellData(globalIdxJ).saturation(wPhaseIdx); + break; + case Sn: + satJ = problem_.variables().cellData(globalIdxJ).saturation(nPhaseIdx); + break; + } + + Scalar localdelta = std::abs(satI - satJ); + indicatorVectorSat_[globalIdxI] = std::max(indicatorVectorSat_[globalIdxI], localdelta); + } + } + } + + if (isSpecialCell) + { + continue; + } + + if (useFluxInd_ || usePercentileFlux_) + { + DimVector refVelocity(0); + for (int i = 0; i < dim; i++) + refVelocity[i] = 0.5 * (flux[2*i + 1] - flux[2*i]); + + const DimVector& localPos = + ReferenceElementContainer::general(eIt->geometry().type()).position(0, 0); + + // get the transposed Jacobian of the element mapping + const DimMatrix& jacobianT = eIt->geometry().jacobianTransposed(localPos); + + // calculate the element velocity by the Piola transformation + DimVector elementVelocity(0); + jacobianT.umtv(refVelocity, elementVelocity); + elementVelocity /= eIt->geometry().integrationElement(localPos); + + Scalar velNorm = elementVelocity.two_norm(); + indicatorVectorFlux_[globalIdxI] = std::max(velNorm, indicatorVectorFlux_[globalIdxI]); + } + + + if (useFluxInd_ || usePercentileFlux_) + { + fluxVec.indicator = indicatorVectorFlux_[globalIdxI]; + fluxVec.volume = volume; + fluxVec.index = globalIdxI; + fluxRange.insert(fluxVec); + } + + if (useSatInd_ || usePercentileSat_) + { + satVec.indicator = indicatorVectorSat_[globalIdxI]; + if (satVec.indicator > 1e-8) + { + satVec.volume = volume; + satVec.index = globalIdxI; + satRange.insert(satVec); + + totalVolumeSat += volume; + } + } + } + + if (useSatInd_ || usePercentileSat_) + { + int range = satRange.size(); + if (range > 0) + { + typename RangeSet::iterator it = satRange.begin(); + Scalar minLocalDelta = (*it).indicator; + + typename RangeSet::reverse_iterator rIt = satRange.rbegin(); + Scalar maxLocalDelta = (*rIt).indicator; + + if (maxLocalDelta > 0.) + { + Scalar globalDeltaDelta = maxLocalDelta - minLocalDelta; + for (int i = 0; i < size; i++) + { + indicatorVectorSat_[i] -= minLocalDelta; + indicatorVectorSat_[i] /= globalDeltaDelta; + } + } + + if (usePercentileSat_) + { + Scalar lowerBound = std::max(0.0,coarsenPercentileSat_ * totalVolumeSat); + + Scalar accumulatedVolume = 0; + while (accumulatedVolume <= lowerBound && it != satRange.end()) + { + indicatorVector_[(*it).index] = coarsenBound_-1; + accumulatedVolume += (*it).volume; + ++it; + } + } + } + } + + if (useFluxInd_ || usePercentileFlux_) + { + int range = fluxRange.size(); + if (range > 0) + { + typename RangeSet::iterator it = fluxRange.begin(); + Scalar minFlux = (*it).indicator; + + typename RangeSet::reverse_iterator rIt = fluxRange.rbegin(); + Scalar maxFlux = (*rIt).indicator; + + if (maxFlux > 0.) + { + Scalar globalDeltaDelta = maxFlux - minFlux; + for (int i = 0; i < size; i++) + { + indicatorVectorFlux_[i] -= minFlux; + indicatorVectorFlux_[i] /= globalDeltaDelta; + } + } + + if (usePercentileFlux_) + { + Scalar lowerBound = std::max(0.0,coarsenPercentileFlux_ * totalVolume); + Scalar accumulatedVolume = 0; + while (accumulatedVolume <= lowerBound && it != fluxRange.end()) + { + indicatorVector_[(*it).index] = coarsenBound_-1; + accumulatedVolume += (*it).volume; + ++it; + } + } + } + } + + if (useSatInd_ || usePercentileSat_) + { + int range = satRange.size(); + if (range > 0) + { + if (usePercentileSat_) + { + typename RangeSet::reverse_iterator rIt = satRange.rbegin(); + + Scalar upperBound = std::max(0.0, refinePercentileSat_ * totalVolumeSat); + + Scalar accumulatedVolume = 0; + while (accumulatedVolume <= upperBound && (*rIt).indicator > 1e-6 && rIt != satRange.rend()) + { + indicatorVector_[(*rIt).index] = refineBound_+1; + accumulatedVolume += (*rIt).volume; + ++rIt; + } + } + + + } + } + + if (useFluxInd_ || usePercentileFlux_) + { + int range = fluxRange.size(); + if (range > 0) + { + typename RangeSet::reverse_iterator rIt = fluxRange.rbegin(); + + if (usePercentileFlux_) + { + Scalar upperBound = std::min(totalVolume, refinePercentileFlux_ * totalVolume); + Scalar accumulatedVolume = 0; + while (accumulatedVolume <= upperBound && rIt != fluxRange.rend()) + { + indicatorVector_[(*rIt).index] = refineBound_+1; + accumulatedVolume += (*rIt).volume; + ++rIt; + } + } + } + } + + for (int idx = 0; idx < size; idx++) + { + if (useSatInd_ && indicatorVectorSat_[idx] > refineThresholdSat_) + { + indicatorVector_[idx] = refineBound_+1; + } + else if (useFluxInd_ && indicatorVectorFlux_[idx] > refineThresholdFlux_) + { + indicatorVector_[idx] = refineBound_+1; + } + else if (useSatInd_ && indicatorVectorSat_[idx] < coarsenThresholdSat_ && indicatorVector_[idx] < refineBound_) + { + indicatorVector_[idx] = coarsenBound_-1; + } + else if (useFluxInd_ && indicatorVectorFlux_[idx] < coarsenThresholdFlux_ && indicatorVector_[idx] < refineBound_) + { + indicatorVector_[idx] = coarsenBound_-1; + } + } + } + + bool checkPhysicalRange_(const CellData& cellData) + { + for (int j = 0; j < 2; j++) + { + if (cellData.pressure(j) < lowerPressureBound_ || cellData.pressure(j) > upperPressureBound_) + return false; + } + return true; + } + + void setPressureBounds(Scalar lowerPressureBound, Scalar upperPressureBound) + { + lowerPressureBound_ = lowerPressureBound; + upperPressureBound_ = upperPressureBound; + } + + /*! \brief Indicator function for marking of grid cells for refinement + * + * Returns true if an element should be refined. + * + * \param element A grid element + */ + bool refine(const Element& element) + { + int idx = problem_.elementMapper().map(element); + return (indicatorVector_[idx] > refineBound_); + } + + /*! \brief Indicator function for marking of grid cells for coarsening + * + * Returns true if an element should be coarsened. + * + * \param element A grid element + */ + bool coarsen(const Element& element) + { + int idx = problem_.elementMapper().map(element); + return (indicatorVector_[idx] < coarsenBound_); + } + + /*! \brief Initializes the adaption indicator class*/ + void init() + { + int size = problem_.gridView().size(0); + + indicatorVector_.resize(size, -1e100); + if (useSatInd_) + indicatorVectorSat_.resize(size, -1e100); + if (useFluxInd_) + indicatorVectorFlux_.resize(size, -1e100); + }; + + void setIndicatorToRefine(int idx) + { + indicatorVector_[idx] = refineBound_+1; + } + + void setIndicatorToCoarse(int idx) + { + indicatorVector_[idx] = coarsenBound_ - 1; + } + + /*! @brief Constructs a GridAdaptionIndicator instance + * + * This standard indicator is based on the saturation gradient. It checks the local gradient compared to the maximum global gradient. + * The indicator is compared locally to a refinement/coarsening threshold to decide whether a cell should be marked for refinement or coarsening or should not be adapted. + * + * \param problem The problem object + */ + GridAdaptionIndicator2PLocalFlux (Problem& problem): + problem_(problem), lowerPressureBound_(0.0), upperPressureBound_(std::numeric_limits<Scalar>::max()) + { + refineThresholdSat_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, RefineThresholdSat); + coarsenThresholdSat_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, CoarsenThresholdSat); + refineBound_ = 2.0; + coarsenBound_ = 1.0; + refineThresholdFlux_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, RefineThresholdFlux); + coarsenThresholdFlux_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, CoarsenThresholdFlux); + refinePercentileFlux_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, RefinePercentileFlux); + coarsenPercentileFlux_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, CoarsenPercentileFlux); + refinePercentileSat_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, RefinePercentileSat); + coarsenPercentileSat_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, GridAdapt, CoarsenPercentileSat); + refineAtDirichletBC_ = GET_PARAM_FROM_GROUP(TypeTag, bool, GridAdapt, RefineAtDirichletBC); + refineAtFluxBC_ = GET_PARAM_FROM_GROUP(TypeTag, bool, GridAdapt, RefineAtFluxBC); + refineAtSource_ = GET_PARAM_FROM_GROUP(TypeTag, bool, GridAdapt, RefineAtSource); + + useSatInd_ = (refineThresholdSat_ < 1.0 || coarsenThresholdSat_ > 0.0); + useFluxInd_ = (refineThresholdFlux_ < 1.0 || coarsenThresholdFlux_ > 0.0); + usePercentileSat_ = (refinePercentileSat_ > 0.0 || coarsenPercentileSat_ > 0.0); + usePercentileFlux_ = (refinePercentileFlux_ > 0.0 || coarsenPercentileFlux_ > 0.0); + + std::cout<<"--------------------------------------------\n"; + std::cout<<"Used adaption indicators:\n"; + if (useSatInd_) + std::cout<<" - delta S\n"; + if (useFluxInd_) + std::cout<<" - total flux\n"; + std::cout<<"\n Use percentiles:\n"; + if (usePercentileSat_) + std::cout<<" - delta S\n"; + if (usePercentileFlux_) + std::cout<<" - total flux\n"; + std::cout<<"--------------------------------------------\n"; + } + +private: + Problem& problem_; + Scalar lowerPressureBound_; + Scalar upperPressureBound_; + bool useSatInd_; + bool useFluxInd_; + bool usePercentileSat_; + bool usePercentileFlux_; + Scalar refineThresholdSat_; + Scalar coarsenThresholdSat_; + Scalar refineBound_; + Scalar coarsenBound_; + Scalar refineThresholdFlux_; + Scalar coarsenThresholdFlux_; + Scalar refinePercentileFlux_; + Scalar coarsenPercentileFlux_; + Scalar refinePercentileSat_; + Scalar coarsenPercentileSat_; + bool refineAtDirichletBC_; + bool refineAtFluxBC_; + bool refineAtSource_; + std::vector<Scalar> indicatorVector_; + std::vector<Scalar> indicatorVectorSat_; + std::vector<Scalar> indicatorVectorFlux_; + static const int saturationType_ = GET_PROP_VALUE(TypeTag, SaturationFormulation); + static const bool compressibility_ = GET_PROP_VALUE(TypeTag, EnableCompressibility); + +}; +} + +#endif -- GitLab