// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /* This file is part of the Open Porous Media project (OPM). OPM 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. OPM 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 OPM. If not, see . Consult the COPYING file in the top-level source directory of this module for the precise wording of the license and the list of copyright holders. */ /*! * \file * * \copydoc Opm::EclThresholdPressure */ #ifndef EWOMS_ECL_THRESHOLD_PRESSURE_HH #define EWOMS_ECL_THRESHOLD_PRESSURE_HH #include #include #include #include #include #include #include #include #include namespace Opm { /*! * \ingroup EclBlackOilSimulator * * \brief This class calculates the threshold pressure for grid faces according to the * Eclipse Reference Manual. * * If the difference of the pressure potential between two cells is below the threshold * pressure, the pressure potential difference is assumed to be zero, if it is larger * than the threshold pressure, it is reduced by the threshold pressure. */ template class EclThresholdPressure : public EclGenericThresholdPressure, GetPropType, GetPropType, GetPropType> { using BaseType = EclGenericThresholdPressure, GetPropType, GetPropType, GetPropType>; using IntensiveQuantities = GetPropType; using ExtensiveQuantities = GetPropType; using Simulator = GetPropType; using Scalar = GetPropType; using Evaluation = GetPropType; using ElementContext = GetPropType; using FluidSystem = GetPropType; using GridView = GetPropType; enum { dimWorld = GridView::dimensionworld }; enum { enableExperiments = getPropValue() }; enum { numPhases = FluidSystem::numPhases }; public: EclThresholdPressure(const Simulator& simulator) : BaseType(simulator.vanguard().cartesianIndexMapper(), simulator.vanguard().gridView(), simulator.model().elementMapper(), simulator.vanguard().eclState(), simulator.vanguard().deck(), enableExperiments) , simulator_(simulator) { } /*! * \brief Actually compute the threshold pressures over a face as a pre-compute step. */ void finishInit() { this->BaseType::finishInit(); if (this->enableThresholdPressure_ && !this->thpresDefault_.empty()) { this->computeDefaultThresholdPressures_(); this->applyExplicitThresholdPressures_(); } } private: template double calculateMaxDp(Face& face, Stencil& stencil, ElemCtx& elemCtx,const unsigned& scvfIdx, const unsigned& i,const unsigned& j,const unsigned& insideElemIdx,const unsigned& outsideElemIdx){ typedef MathToolbox Toolbox; elemCtx.updateIntensiveQuantities(/*timeIdx=*/0); elemCtx.updateExtensiveQuantities(/*timeIdx=*/0); // determine the maximum difference of the pressure of any phase over the // intersection Scalar pth = 0.0; const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, /*timeIdx=*/0); for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { unsigned upIdx = extQuants.upstreamIndex(phaseIdx); const auto& up = elemCtx.intensiveQuantities(upIdx, /*timeIdx=*/0); if (up.mobility(phaseIdx) > 0.0) { Scalar phaseVal = Toolbox::value(extQuants.pressureDifference(phaseIdx)); pth = std::max(pth, std::abs(phaseVal)); } } return pth; } template double calculateMaxDp(Face& face, Stencil& stencil, SmallElementContext& elemCtx,const unsigned& scvfIdx, const unsigned& i,const unsigned& j, const unsigned& insideElemIdx,const unsigned& outsideElemIdx){ typedef MathToolbox Toolbox; // determine the maximum difference of the pressure of any phase over the // intersection Scalar pth = 0.0; //const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, /*timeIdx=*/0); Scalar Vin = elemCtx.dofVolume(i, /*timeIdx=*/0); Scalar Vex = elemCtx.dofVolume(j, /*timeIdx=*/0); Scalar thpres = 0.0;//NB ??problem.thresholdPressure(globalIndexIn, globalIndexEx); // estimate the gravity correction: for performance reasons we use a simplified // approach for this flux module that assumes that gravity is constant and always // acts into the downwards direction. (i.e., no centrifuge experiments, sorry.) const auto& problem = elemCtx.problem(); Scalar g = problem.gravity()[dimWorld - 1]; const auto& intQuantsIn = elemCtx.intensiveQuantities(i, /*timeIdx*/0); const auto& intQuantsEx = elemCtx.intensiveQuantities(j, /*timeIdx*/0); // this is quite hacky because the dune grid interface does not provide a // cellCenterDepth() method (so we ask the problem to provide it). The "good" // solution would be to take the Z coordinate of the element centroids, but since // ECL seems to like to be inconsistent on that front, it needs to be done like // here... Scalar zIn = problem.dofCenterDepth(elemCtx, i, /*timeIdx*/0); Scalar zEx = problem.dofCenterDepth(elemCtx, j, /*timeIdx*/0); // the distances from the DOF's depths. (i.e., the additional depth of the // exterior DOF) Scalar distZ = zIn - zEx; for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { short dnIdx; // short upIdx; Evaluation pressureDifference; ExtensiveQuantities::calculatePhasePressureDiff_(upIdx, dnIdx, pressureDifference, intQuantsIn, intQuantsEx, /*timeIdx*/0,//input phaseIdx,//input i,//input j,//intput Vin, Vex, insideElemIdx, outsideElemIdx, distZ*g, thpres); const IntensiveQuantities& up = (upIdx == i) ? intQuantsIn : intQuantsEx; if (up.mobility(phaseIdx) > 0.0) { Scalar phaseVal = Toolbox::value(pressureDifference); pth = std::max(pth, std::abs(phaseVal)); } } return pth; } // compute the defaults of the threshold pressures using the initial condition void computeDefaultThresholdPressures_() { const auto& vanguard = simulator_.vanguard(); const auto& gridView = vanguard.gridView(); typedef MathToolbox Toolbox; // loop over the whole grid and compute the maximum gravity adjusted pressure // difference between two EQUIL regions. auto elemIt = gridView.template begin(); const auto& elemEndIt = gridView.template end(); ElementContext elemCtx(simulator_); simulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0); for (; elemIt != elemEndIt; ++elemIt) { const auto& elem = *elemIt; if (elem.partitionType() != Dune::InteriorEntity) continue; elemCtx.updateStencil(elem); // const auto& stencil = elemCtx.stencil(/*timeIdx=*/0); for (unsigned scvfIdx = 0; scvfIdx < stencil.numInteriorFaces(); ++ scvfIdx) { const auto& face = stencil.interiorFace(scvfIdx); unsigned i = face.interiorIndex(); unsigned j = face.exteriorIndex(); unsigned insideElemIdx = elemCtx.globalSpaceIndex(i, /*timeIdx=*/0); unsigned outsideElemIdx = elemCtx.globalSpaceIndex(j, /*timeIdx=*/0); unsigned equilRegionInside = this->elemEquilRegion_[insideElemIdx]; unsigned equilRegionOutside = this->elemEquilRegion_[outsideElemIdx]; if (equilRegionInside == equilRegionOutside) // the current face is not at the boundary between EQUIL regions! continue; const auto& problem = elemCtx.problem(); // don't include connections with negligible flow const Evaluation& trans = problem.transmissibility(elemCtx, i, j); Scalar faceArea = face.area(); if (std::abs(faceArea*getValue(trans)) < 1e-18) continue; double pth = calculateMaxDp(face, stencil, elemCtx, scvfIdx, i, j, insideElemIdx, outsideElemIdx); // don't include connections with negligible flow int offset1 = equilRegionInside*this->numEquilRegions_ + equilRegionOutside; int offset2 = equilRegionOutside*this->numEquilRegions_ + equilRegionInside; this->thpresDefault_[offset1] = std::max(this->thpresDefault_[offset1], pth); this->thpresDefault_[offset2] = std::max(this->thpresDefault_[offset2], pth); } } // make sure that the threshold pressures is consistent for parallel // runs. (i.e. take the maximum of all processes) for (unsigned i = 0; i < this->thpresDefault_.size(); ++i) this->thpresDefault_[i] = gridView.comm().max(this->thpresDefault_[i]); } const Simulator& simulator_; }; } // namespace Opm #endif