/* Copyright (C) 2014 by Andreas Lauser 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 . */ /** * \file * * \copydoc Ewoms::EclEquilInitializer */ #ifndef EWOMS_ECL_EQUIL_INITIALIZER_HH #define EWOMS_ECL_EQUIL_INITIALIZER_HH #include // the ordering of these includes matters. do not touch it if you're not prepared to deal // with some trouble! #include #include #include #include #include namespace Ewoms { /*! * \ingroup EclBlackOilSimulator * * \brief Computes the initial condition based on the EQUIL keyword from ECL. * * So far, it uses the "initStateEquil()" function from opm-core. Since this method is * very much glued into the opm-core data structures, it should be reimplemented in the * medium to long term for some significant memory savings and less significant * performance improvements. */ template class EclEquilInitializer { typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator; typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; typedef Opm::CompositionalFluidState ScalarFluidState; enum { numPhases = FluidSystem::numPhases }; enum { oilPhaseIdx = FluidSystem::oilPhaseIdx }; enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; enum { waterPhaseIdx = FluidSystem::waterPhaseIdx }; enum { numComponents = FluidSystem::numComponents }; enum { oilCompIdx = FluidSystem::oilCompIdx }; enum { gasCompIdx = FluidSystem::gasCompIdx }; enum { waterCompIdx = FluidSystem::waterCompIdx }; enum { dimWorld = GridView::dimensionworld }; public: template EclEquilInitializer(const Simulator& simulator, std::shared_ptr materialLawManager) : simulator_(simulator) { const auto& gridManager = simulator.gridManager(); const auto& equilGrid = gridManager.equilGrid(); // create the data structures which are used by initStateEquil() Opm::parameter::ParameterGroup tmpParam; Opm::BlackoilPropertiesFromDeck opmBlackoilProps( gridManager.deck(), gridManager.eclState(), materialLawManager, Opm::UgGridHelpers::numCells(equilGrid), Opm::UgGridHelpers::globalCell(equilGrid), Opm::UgGridHelpers::cartDims(equilGrid), tmpParam); const unsigned numElems = equilGrid.size(/*codim=*/0); assert( gridManager.grid().size(/*codim=*/0) == static_cast(numElems) ); // initialize the boiler plate of opm-core the state structure. Opm::BlackoilState opmBlackoilState; opmBlackoilState.init(numElems, /*numFaces=*/0, // we don't care here numPhases); // do the actual computation. Opm::initStateEquil(equilGrid, opmBlackoilProps, gridManager.deck(), gridManager.eclState(), simulator.problem().gravity()[dimWorld - 1], opmBlackoilState); const Scalar rhooRef = FluidSystem::referenceDensity(oilPhaseIdx, /*regionIdx=*/0); const Scalar rhogRef = FluidSystem::referenceDensity(gasPhaseIdx, /*regionIdx=*/0); const Scalar MG = FluidSystem::molarMass(gasCompIdx); const Scalar MO = FluidSystem::molarMass(oilCompIdx); // copy the result into the array of initial fluid states initialFluidStates_.resize(numElems); for (unsigned elemIdx = 0; elemIdx < numElems; ++elemIdx) { auto &fluidState = initialFluidStates_[elemIdx]; // get the PVT region index of the current element unsigned regionIdx = simulator_.problem().pvtRegionIndex(elemIdx); // set the phase saturations for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { Scalar S = opmBlackoilState.saturation()[elemIdx*numPhases + phaseIdx]; fluidState.setSaturation(phaseIdx, S); } // set the temperature const auto& temperatureVector = opmBlackoilState.temperature(); Scalar T = FluidSystem::surfaceTemperature; if (!temperatureVector.empty()) T = temperatureVector[elemIdx]; fluidState.setTemperature(T); // set the phase pressures. the Opm::BlackoilState only provides the oil // phase pressure, so we need to calculate the other phases' pressures // ourselfs. Dune::FieldVector< Scalar, numPhases > pC( 0 ); const auto& matParams = simulator.problem().materialLawParams(elemIdx); MaterialLaw::capillaryPressures(pC, matParams, fluidState); Scalar po = opmBlackoilState.pressure()[elemIdx]; for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) fluidState.setPressure(phaseIdx, po + (pC[phaseIdx] - pC[oilPhaseIdx])); Scalar pg = fluidState.pressure(gasPhaseIdx); // reset the phase compositions for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) fluidState.setMoleFraction(phaseIdx, compIdx, 0.0); // the composition of the water phase is simple: it only consists of the // water component. fluidState.setMoleFraction(waterPhaseIdx, waterCompIdx, 1.0); if (gridManager.deck()->hasKeyword("DISGAS")) { // for gas and oil we have to translate surface volumes to mole fractions // before we can set the composition in the fluid state Scalar Rs = opmBlackoilState.gasoilratio()[elemIdx]; // dissolved gas surface volume to mass fraction Scalar XoG = Rs/(rhooRef/rhogRef + Rs); // mass fraction to mole fraction Scalar xoG = XoG*MO / (MG*(1 - XoG) + XoG*MO); Scalar xoGMax = FluidSystem::saturatedOilGasMoleFraction(T, pg, regionIdx); if (fluidState.saturation(gasPhaseIdx) > 0.0 || xoG > xoGMax) xoG = xoGMax; fluidState.setMoleFraction(oilPhaseIdx, oilCompIdx, 1 - xoG); fluidState.setMoleFraction(oilPhaseIdx, gasCompIdx, xoG); } // retrieve the surface volume of vaporized gas if (gridManager.deck()->hasKeyword("VAPOIL")) { Scalar Rv = opmBlackoilState.rv()[elemIdx]; // vaporized oil surface volume to mass fraction Scalar XgO = Rv/(rhogRef/rhooRef + Rv); // mass fraction to mole fraction Scalar xgO = XgO*MG / (MO*(1 - XgO) + XgO*MG); Scalar xgOMax = FluidSystem::saturatedGasOilMoleFraction(T, pg, regionIdx); if (fluidState.saturation(oilPhaseIdx) > 0.0 || xgO > xgOMax) xgO = xgOMax; fluidState.setMoleFraction(gasPhaseIdx, oilCompIdx, xgO); fluidState.setMoleFraction(gasPhaseIdx, gasCompIdx, 1 - xgO); } } } /*! * \brief Return the initial thermodynamic state which should be used as the initial * condition. * * This is supposed to correspond to hydrostatic conditions. */ const ScalarFluidState& initialFluidState(unsigned elemIdx) const { return initialFluidStates_[elemIdx]; } protected: const Simulator& simulator_; std::vector initialFluidStates_; }; } // namespace Ewoms #endif