diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index ad147010f22..054a6b509dc 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -481,6 +481,7 @@ list (APPEND TEST_SOURCE_FILES tests/test_ALQState.cpp tests/test_aquifergridutils.cpp tests/test_blackoil_amg.cpp + tests/test_blackoilprimaryvariables.cpp tests/test_convergenceoutputconfiguration.cpp tests/test_convergencereport.cpp tests/test_deferredlogger.cpp diff --git a/tests/test_blackoilprimaryvariables.cpp b/tests/test_blackoilprimaryvariables.cpp new file mode 100644 index 00000000000..a44471b8adb --- /dev/null +++ b/tests/test_blackoilprimaryvariables.cpp @@ -0,0 +1,338 @@ +#include + +#include "TestTypeTag.hpp" + +#include + +#define BOOST_TEST_MODULE BlackoilPrimaryVariables +#include + +#include +#include +#include +#include + +struct ZeroCapillaryMaterialLaw +{ + struct Params {}; + + template + static void capillaryPressures(Container& result, const Params&, const FluidState&) + { + for (auto& value : result) { + value = 0.0; + } + } +}; + +template +class StubBlackoilPrimaryVariablesProblem +{ +public: + using MaterialLawParams = Opm::GetPropType; + + unsigned satnumRegionIndex(unsigned) const + { + return 0; + } + + double temperature(unsigned, unsigned) const + { + return 300.0; + } + + double referencePorosity(unsigned, unsigned) const + { + return 0.0; + } + + const MaterialLawParams& materialLawParams(unsigned) const + { + return materialLawParams_; + } + + double maxGasDissolutionFactor(unsigned, unsigned) const + { + return 1.0; + } + + double maxOilSaturation(unsigned) const + { + return 1.0; + } + + double maxOilVaporizationFactor(unsigned, unsigned) const + { + return 1.0; + } + +private: + MaterialLawParams materialLawParams_{}; +}; + +namespace Opm::Properties { + +namespace TTag { + +struct ClassicalBlackoilPrimaryVariablesTestTypeTag { + using InheritsFrom = std::tuple; +}; + +} // namespace TTag + +template +struct Problem +{ + using type = ::StubBlackoilPrimaryVariablesProblem; +}; + +template +struct MaterialLaw +{ + using type = ::ZeroCapillaryMaterialLaw; +}; + +} // namespace Opm::Properties + +namespace { + +using TypeTag = Opm::Properties::TTag::ClassicalBlackoilPrimaryVariablesTestTypeTag; +using PrimaryVariables = Opm::BlackOilPrimaryVariables; +using FluidSystem = Opm::GetPropType; +using Indices = Opm::GetPropType; +using Problem = Opm::GetPropType; +using GasPvt = typename FluidSystem::GasPvt; +using OilPvt = typename FluidSystem::OilPvt; + +static_assert(Opm::getPropValue() + == Opm::EnergyModules::NoTemperature); + +struct FluidSystemGuard +{ + FluidSystemGuard() + : dissolvedGas(FluidSystem::enableDissolvedGas()) + , dissolvedGasInWater(FluidSystem::enableDissolvedGasInWater()) + , vaporizedOil(FluidSystem::enableVaporizedOil()) + , vaporizedWater(FluidSystem::enableVaporizedWater()) + , reservoirTemperature(FluidSystem::reservoirTemperature()) + , gasPvt(FluidSystem::gasPvt()) + , oilPvt(FluidSystem::oilPvt()) + { + } + + ~FluidSystemGuard() + { + FluidSystem::setGasPvt(std::make_shared(gasPvt)); + FluidSystem::setOilPvt(std::make_shared(oilPvt)); + FluidSystem::setReservoirTemperature(reservoirTemperature); + FluidSystem::setEnableVaporizedWater(vaporizedWater); + FluidSystem::setEnableVaporizedOil(vaporizedOil); + FluidSystem::setEnableDissolvedGasInWater(dissolvedGasInWater); + FluidSystem::setEnableDissolvedGas(dissolvedGas); + } + + bool dissolvedGas; + bool dissolvedGasInWater; + bool vaporizedOil; + bool vaporizedWater; + double reservoirTemperature; + GasPvt gasPvt; + OilPvt oilPvt; +}; + +PrimaryVariables makePrimaryVariables(PrimaryVariables::GasMeaning gasMeaning, + double waterSwitch, + double compositionSwitch, + PrimaryVariables::WaterMeaning waterMeaning = PrimaryVariables::WaterMeaning::Sw, + PrimaryVariables::PressureMeaning pressureMeaning = PrimaryVariables::PressureMeaning::Po, + double pressure = 0.0) +{ + PrimaryVariables priVars; + for (std::size_t i = 0; i < priVars.size(); ++i) { + priVars[i] = 0.0; + } + + priVars.setPrimaryVarsMeaningWater(waterMeaning); + priVars.setPrimaryVarsMeaningGas(gasMeaning); + priVars.setPrimaryVarsMeaningPressure(pressureMeaning); + priVars.setPrimaryVarsMeaningBrine(PrimaryVariables::BrineMeaning::Disabled); + priVars.setPrimaryVarsMeaningSolvent(PrimaryVariables::SolventMeaning::Disabled); + priVars[Indices::waterSwitchIdx] = waterSwitch; + priVars[Indices::compositionSwitchIdx] = compositionSwitch; + priVars[Indices::pressureSwitchIdx] = pressure; + return priVars; +} + +std::shared_ptr makeConstantRsOilPvt(double rsSat) +{ + auto oilPvt = std::make_shared(); + oilPvt->setApproach(Opm::OilPvtApproach::ConstantRsDeadOil); + auto& realOilPvt = oilPvt->template getRealPvt(); + realOilPvt.setNumRegions(1); + realOilPvt.setConstantRs(rsSat); + realOilPvt.setBubblePointPressure(0.0); + return oilPvt; +} + +std::shared_ptr makeWetGasPvt(double rvSat) +{ + auto gasPvt = std::make_shared(); + gasPvt->setApproach(Opm::GasPvtApproach::WetGas); + auto& realGasPvt = gasPvt->template getRealPvt(); + realGasPvt.setNumRegions(1); + realGasPvt.setSaturatedGasOilVaporizationFactor(0, + {{1.0e5, rvSat}, + {2.0e5, rvSat}}); + return gasPvt; +} + +} // namespace + +BOOST_AUTO_TEST_CASE(AdaptPrimaryVariablesSwitchesToGasSaturationInWaterFilledCells) +{ + FluidSystemGuard guard; + FluidSystem::setEnableDissolvedGasInWater(false); + FluidSystem::setReservoirTemperature(300.0); + + Problem problem; + auto priVars = makePrimaryVariables(PrimaryVariables::GasMeaning::Rs, 1.2, 0.37); + + const bool changed = priVars.adaptPrimaryVariables(problem, + /*globalDofIdx=*/0, + /*swMaximum=*/1.0, + /*thresholdWaterFilledCell=*/0.95); + + BOOST_CHECK(changed); + BOOST_CHECK(priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg); + BOOST_CHECK(priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Sw); + BOOST_CHECK_CLOSE(priVars[Indices::waterSwitchIdx], 1.0, 1e-12); + BOOST_CHECK_SMALL(priVars[Indices::compositionSwitchIdx], 1e-12); +} + +BOOST_AUTO_TEST_CASE(AdaptPrimaryVariablesKeepsGasMeaningWhenAlreadySg) +{ + FluidSystemGuard guard; + FluidSystem::setEnableDissolvedGasInWater(false); + FluidSystem::setReservoirTemperature(300.0); + + Problem problem; + auto priVars = makePrimaryVariables(PrimaryVariables::GasMeaning::Sg, 1.1, 0.44); + + const bool changed = priVars.adaptPrimaryVariables(problem, + /*globalDofIdx=*/0, + /*swMaximum=*/1.0, + /*thresholdWaterFilledCell=*/0.95); + + BOOST_CHECK(!changed); + BOOST_CHECK(priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg); + BOOST_CHECK_CLOSE(priVars[Indices::waterSwitchIdx], 1.0, 1e-12); + BOOST_CHECK_SMALL(priVars[Indices::compositionSwitchIdx], 1e-12); +} + +BOOST_AUTO_TEST_CASE(AdaptPrimaryVariablesSwitchesFromGasSaturationToRs) +{ + FluidSystemGuard guard; + FluidSystem::setEnableDissolvedGas(true); + FluidSystem::setEnableDissolvedGasInWater(false); + FluidSystem::setEnableVaporizedOil(false); + FluidSystem::setEnableVaporizedWater(false); + FluidSystem::setReservoirTemperature(300.0); + FluidSystem::setOilPvt(makeConstantRsOilPvt(0.25)); + + Problem problem; + auto priVars = makePrimaryVariables(PrimaryVariables::GasMeaning::Sg, 0.2, -0.05); + + const bool changed = priVars.adaptPrimaryVariables(problem, + /*globalDofIdx=*/0, + /*swMaximum=*/1.0, + /*thresholdWaterFilledCell=*/1.1); + + BOOST_CHECK(changed); + BOOST_CHECK(priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rs); + BOOST_CHECK(priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Po); + BOOST_CHECK_CLOSE(priVars[Indices::compositionSwitchIdx], 0.25, 1e-12); +} + +BOOST_AUTO_TEST_CASE(AdaptPrimaryVariablesSwitchesFromRsToGasSaturation) +{ + FluidSystemGuard guard; + FluidSystem::setEnableDissolvedGas(true); + FluidSystem::setEnableDissolvedGasInWater(false); + FluidSystem::setEnableVaporizedOil(false); + FluidSystem::setEnableVaporizedWater(false); + FluidSystem::setReservoirTemperature(300.0); + FluidSystem::setOilPvt(makeConstantRsOilPvt(0.25)); + + Problem problem; + auto priVars = makePrimaryVariables(PrimaryVariables::GasMeaning::Rs, 0.2, 0.3); + + const bool changed = priVars.adaptPrimaryVariables(problem, + /*globalDofIdx=*/0, + /*swMaximum=*/1.0, + /*thresholdWaterFilledCell=*/1.1); + + BOOST_CHECK(changed); + BOOST_CHECK(priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg); + BOOST_CHECK(priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Po); + BOOST_CHECK_SMALL(priVars[Indices::compositionSwitchIdx], 1e-12); +} + +BOOST_AUTO_TEST_CASE(AdaptPrimaryVariablesSwitchesFromGasSaturationToRv) +{ + FluidSystemGuard guard; + FluidSystem::setEnableDissolvedGas(false); + FluidSystem::setEnableDissolvedGasInWater(false); + FluidSystem::setEnableVaporizedOil(true); + FluidSystem::setEnableVaporizedWater(false); + FluidSystem::setReservoirTemperature(300.0); + FluidSystem::setGasPvt(makeWetGasPvt(0.15)); + + Problem problem; + auto priVars = makePrimaryVariables(PrimaryVariables::GasMeaning::Sg, + 0.4, + 0.7, + PrimaryVariables::WaterMeaning::Sw, + PrimaryVariables::PressureMeaning::Po, + 1.5e5); + + const bool changed = priVars.adaptPrimaryVariables(problem, + /*globalDofIdx=*/0, + /*swMaximum=*/1.0, + /*thresholdWaterFilledCell=*/1.1); + + BOOST_CHECK(changed); + BOOST_CHECK(priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rv); + BOOST_CHECK(priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pg); + BOOST_CHECK_CLOSE(priVars[Indices::compositionSwitchIdx], 0.15, 1e-12); + BOOST_CHECK_CLOSE(priVars[Indices::pressureSwitchIdx], 1.5e5, 1e-12); +} + +BOOST_AUTO_TEST_CASE(AdaptPrimaryVariablesSwitchesFromRvToGasSaturation) +{ + FluidSystemGuard guard; + FluidSystem::setEnableDissolvedGas(false); + FluidSystem::setEnableDissolvedGasInWater(false); + FluidSystem::setEnableVaporizedOil(true); + FluidSystem::setEnableVaporizedWater(false); + FluidSystem::setReservoirTemperature(300.0); + FluidSystem::setGasPvt(makeWetGasPvt(0.15)); + + Problem problem; + auto priVars = makePrimaryVariables(PrimaryVariables::GasMeaning::Rv, + 0.2, + 0.3, + PrimaryVariables::WaterMeaning::Sw, + PrimaryVariables::PressureMeaning::Pg, + 1.5e5); + + const bool changed = priVars.adaptPrimaryVariables(problem, + /*globalDofIdx=*/0, + /*swMaximum=*/1.0, + /*thresholdWaterFilledCell=*/1.1); + + BOOST_CHECK(changed); + BOOST_CHECK(priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg); + BOOST_CHECK(priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Po); + BOOST_CHECK_CLOSE(priVars[Indices::compositionSwitchIdx], 0.8, 1e-12); + BOOST_CHECK_CLOSE(priVars[Indices::pressureSwitchIdx], 1.5e5, 1e-12); +} \ No newline at end of file