diff --git a/integratedTests b/integratedTests index 86a71b88158..860c6933814 160000 --- a/integratedTests +++ b/integratedTests @@ -1 +1 @@ -Subproject commit 86a71b88158ecdb1bc6593279d43853f22af6fff +Subproject commit 860c69338149e56dbc5ab3743d00ebead3cb631d diff --git a/src/coreComponents/constitutive/CMakeLists.txt b/src/coreComponents/constitutive/CMakeLists.txt index 1fbe7d875fb..92105bec8a6 100644 --- a/src/coreComponents/constitutive/CMakeLists.txt +++ b/src/coreComponents/constitutive/CMakeLists.txt @@ -15,14 +15,14 @@ set( constitutive_headers contact/Coulomb.hpp fluid/DeadOilFluid.hpp fluid/MultiPhaseMultiComponentFluid.hpp - fluid/PVTFunctions/BrineCO2DensityFunction.hpp - fluid/PVTFunctions/BrineViscosityFunction.hpp - fluid/PVTFunctions/CO2SolubilityFunction.hpp - fluid/PVTFunctions/FenghourCO2ViscosityFunction.hpp + fluid/PVTFunctions/BrineCO2Density.hpp + fluid/PVTFunctions/BrineViscosity.hpp + fluid/PVTFunctions/CO2Solubility.hpp + fluid/PVTFunctions/FenghourCO2Viscosity.hpp fluid/PVTFunctions/FlashModelBase.hpp fluid/PVTFunctions/PVTFunctionBase.hpp - fluid/PVTFunctions/SpanWagnerCO2DensityFunction.hpp - fluid/PVTFunctions/UtilityFunctions.hpp + fluid/PVTFunctions/SpanWagnerCO2Density.hpp + fluid/PVTFunctions/PVTFunctionHelpers.hpp fluid/SingleFluidBase.hpp fluid/singleFluidSelector.hpp fluid/MultiFluidBase.hpp @@ -75,13 +75,12 @@ set( constitutive_sources contact/Coulomb.cpp fluid/DeadOilFluid.cpp fluid/CompressibleSinglePhaseFluid.cpp - fluid/MultiPhaseMultiComponentFluid.cpp - fluid/PVTFunctions/BrineCO2DensityFunction.cpp - fluid/PVTFunctions/BrineViscosityFunction.cpp - fluid/PVTFunctions/CO2SolubilityFunction.cpp - fluid/PVTFunctions/FenghourCO2ViscosityFunction.cpp - fluid/PVTFunctions/SpanWagnerCO2DensityFunction.cpp - fluid/PVTFunctions/UtilityFunctions.cpp + fluid/MultiPhaseMultiComponentFluid.cpp + fluid/PVTFunctions/BrineCO2Density.cpp + fluid/PVTFunctions/BrineViscosity.cpp + fluid/PVTFunctions/CO2Solubility.cpp + fluid/PVTFunctions/FenghourCO2Viscosity.cpp + fluid/PVTFunctions/SpanWagnerCO2Density.cpp fluid/SingleFluidBase.cpp fluid/MultiFluidBase.cpp fluid/CompressibleSinglePhaseFluid.cpp diff --git a/src/coreComponents/constitutive/docs/CO2Brine.rst b/src/coreComponents/constitutive/docs/CO2Brine.rst index 5c1d3135938..2a2e26c3dfe 100644 --- a/src/coreComponents/constitutive/docs/CO2Brine.rst +++ b/src/coreComponents/constitutive/docs/CO2Brine.rst @@ -189,11 +189,11 @@ where :math:`m` is the user-defined salinity. Parameters ========================= -The model is represented by ```` node in the input. +The model is represented by ```` node in the input. The following attributes are supported: -.. include:: ../../../coreComponents/fileIO/schema/docs/MultiPhaseMultiComponentFluid.rst +.. include:: ../../../coreComponents/fileIO/schema/docs/CO2BrineFluid.rst Supported phase names are: @@ -219,7 +219,7 @@ Example .. code-block:: xml - const & phaseCompFraction, real64 & totalDensity ) const override; - //GEOSX_HOST_DEVICE + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE virtual void compute( real64 const pressure, real64 const temperature, @@ -164,7 +164,7 @@ class DeadOilFluidUpdate final : public MultiFluidBaseUpdate real64 & dTotalDensity_dTemperature, arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const override; - //GEOSX_HOST_DEVICE + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE virtual void update( localIndex const k, localIndex const q, @@ -203,24 +203,24 @@ class DeadOilFluidUpdate final : public MultiFluidBaseUpdate private: - //GEOSX_HOST_DEVICE + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void computeDensities( real64 pressure, arraySlice1d< real64 > const & phaseMassDens ) const; - //GEOSX_HOST_DEVICE + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void computeDensities( real64 pressure, arraySlice1d< real64 > const & phaseMassDens, arraySlice1d< real64 > const & dPhaseMassDens_dPres, arraySlice2d< real64 > const & dPhaseMassDens_dGlobalCompFrac ) const; - //GEOSX_HOST_DEVICE + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void computeViscosities( real64 pressure, arraySlice1d< real64 > const & phaseVisc ) const; - //GEOSX_HOST_DEVICE + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void computeViscosities( real64 pressure, arraySlice1d< real64 > const & phaseVisc, @@ -260,6 +260,8 @@ class DeadOilFluid : public MultiFluidBase { public: + using exec_policy = parallelDevicePolicy<>; + struct PhaseType { static constexpr integer OIL = 0; @@ -432,7 +434,7 @@ class DeadOilFluid : public MultiFluidBase }; -//GEOSX_HOST_DEVICE +GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void DeadOilFluidUpdate::computeDensities( real64 pressure, arraySlice1d< real64 > const & phaseMassDens ) const @@ -467,7 +469,7 @@ void DeadOilFluidUpdate::computeDensities( real64 pressure, } } -//GEOSX_HOST_DEVICE +GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void DeadOilFluidUpdate::computeDensities( real64 pressure, arraySlice1d< real64 > const & phaseMassDens, @@ -516,7 +518,7 @@ void DeadOilFluidUpdate::computeDensities( real64 pressure, } } -//GEOSX_HOST_DEVICE +GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void DeadOilFluidUpdate::computeViscosities( real64 pressure, arraySlice1d< real64, 0 > const & phaseVisc ) const @@ -547,7 +549,7 @@ void DeadOilFluidUpdate::computeViscosities( real64 pressure, } } -//GEOSX_HOST_DEVICE +GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void DeadOilFluidUpdate::computeViscosities( real64 pressure, arraySlice1d< real64 > const & phaseVisc, @@ -583,7 +585,7 @@ void DeadOilFluidUpdate::computeViscosities( real64 pressure, } } -//GEOSX_HOST_DEVICE +GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void DeadOilFluidUpdate::compute( real64 pressure, real64 temperature, @@ -632,7 +634,7 @@ void DeadOilFluidUpdate::compute( real64 pressure, totalDens = 1.0 / totalDens; } -//GEOSX_HOST_DEVICE +GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE void DeadOilFluidUpdate::compute( real64 pressure, real64 temperature, @@ -660,7 +662,7 @@ void DeadOilFluidUpdate::compute( real64 pressure, real64 & totalDensity, real64 & dTotalDensity_dPressure, real64 & dTotalDensity_dTemperature, - arraySlice1d< real64, 0 > const & dTotalDensity_dGlobalCompFraction ) const + arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const { GEOSX_UNUSED_VAR( temperature ); GEOSX_UNUSED_VAR( dPhaseFraction_dTemperature ); @@ -702,7 +704,7 @@ void DeadOilFluidUpdate::compute( real64 pressure, dPhaseFraction_dPressure[ip] = 0.0; for( localIndex ic = 0; ic < nComps; ++ic ) { - dPhaseFraction_dGlobalCompFraction[ip][ic] = (ip == ic) ? 1-composition[ip] : -composition[ip]; + dPhaseFraction_dGlobalCompFraction[ip][ic] = (ip == ic) ? 1.0 : 0.0; phaseCompFraction[ip][ic] = (ip == ic) ? 1.0 : 0.0; dPhaseCompFraction_dPressure[ip][ic] = 0.0; diff --git a/src/coreComponents/constitutive/fluid/MultiFluidBase.hpp b/src/coreComponents/constitutive/fluid/MultiFluidBase.hpp index 7518d30c4e5..68bf732cdb6 100644 --- a/src/coreComponents/constitutive/fluid/MultiFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/MultiFluidBase.hpp @@ -163,6 +163,7 @@ class MultiFluidBaseUpdate private: + GEOSX_HOST_DEVICE virtual void compute( real64 const pressure, real64 const temperature, arraySlice1d< real64 const > const & composition, @@ -173,6 +174,7 @@ class MultiFluidBaseUpdate arraySlice2d< real64 > const & phaseCompFraction, real64 & totalDensity ) const = 0; + GEOSX_HOST_DEVICE virtual void compute( real64 const pressure, real64 const temperature, arraySlice1d< real64 const > const & composition, @@ -201,12 +203,12 @@ class MultiFluidBaseUpdate real64 & dTotalDensity_dTemperature, arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const = 0; + GEOSX_HOST_DEVICE virtual void update( localIndex const k, localIndex const q, real64 const pressure, real64 const temperature, arraySlice1d< real64 const > const & composition ) const = 0; - }; class MultiFluidBase : public ConstitutiveBase diff --git a/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.cpp b/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.cpp index 3f5ca015e79..25d60bd7467 100644 --- a/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.cpp +++ b/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.cpp @@ -81,6 +81,7 @@ MultiFluidPVTPackageWrapper::deliverClone( string const & name, return clone; } +GEOSX_HOST_DEVICE void MultiFluidPVTPackageWrapperUpdate::compute( real64 pressure, real64 temperature, arraySlice1d< real64 const > const & composition, @@ -91,6 +92,9 @@ void MultiFluidPVTPackageWrapperUpdate::compute( real64 pressure, arraySlice2d< real64 > const & phaseCompFrac, real64 & totalDens ) const { +#if defined(__CUDA_ARCH__) + GEOSX_ERROR( "This function cannot be used on GPU" ); +#else localIndex const NC = m_componentMolarWeight.size(); localIndex const NP = m_phaseTypes.size(); @@ -195,8 +199,10 @@ void MultiFluidPVTPackageWrapperUpdate::compute( real64 pressure, // 5.2. Invert the previous quantity to get actual density totalDens = 1.0 / totalDens; } +#endif } +GEOSX_HOST_DEVICE void MultiFluidPVTPackageWrapperUpdate::compute( real64 pressure, real64 temperature, arraySlice1d< real64 const > const & composition, @@ -225,6 +231,9 @@ void MultiFluidPVTPackageWrapperUpdate::compute( real64 pressure, real64 & dTotalDensity_dTemperature, arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const { +#if defined(__CUDA_ARCH__) + GEOSX_ERROR( "This function cannot be used on GPU" ); +#else // 0. make shortcut structs to avoid long names (TODO maybe remove) CompositionalVarContainer< 1 > phaseFrac{ phaseFraction, @@ -268,11 +277,6 @@ void MultiFluidPVTPackageWrapperUpdate::compute( real64 pressure, dTotalDensity_dGlobalCompFraction }; -#if defined(__CUDACC__) - // For some reason nvcc thinks these aren't used. - GEOSX_UNUSED_VAR( phaseFrac, phaseDens, phaseMassDens, phaseVisc, phaseCompFrac, totalDens ); -#endif - localIndex constexpr maxNumComp = MultiFluidBase::MAX_NUM_COMPONENTS; localIndex const NC = numComponents(); localIndex const NP = numPhases(); @@ -489,6 +493,7 @@ void MultiFluidPVTPackageWrapperUpdate::compute( real64 pressure, totalDens.dComp[jc] *= minusDens2; } } +#endif } } //namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.hpp b/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.hpp index 6d34e357485..a5664f38b21 100644 --- a/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.hpp +++ b/src/coreComponents/constitutive/fluid/MultiFluidPVTPackageWrapper.hpp @@ -117,6 +117,7 @@ class MultiFluidPVTPackageWrapperUpdate final : public MultiFluidBaseUpdate /// Deleted move assignment operator MultiFluidPVTPackageWrapperUpdate & operator=( MultiFluidPVTPackageWrapperUpdate && ) = delete; + GEOSX_HOST_DEVICE virtual void compute( real64 const pressure, real64 const temperature, arraySlice1d< real64 const > const & composition, @@ -127,6 +128,7 @@ class MultiFluidPVTPackageWrapperUpdate final : public MultiFluidBaseUpdate arraySlice2d< real64 > const & phaseCompFraction, real64 & totalDensity ) const override; + GEOSX_HOST_DEVICE virtual void compute( real64 const pressure, real64 const temperature, arraySlice1d< real64 const > const & composition, @@ -155,6 +157,7 @@ class MultiFluidPVTPackageWrapperUpdate final : public MultiFluidBaseUpdate real64 & dTotalDensity_dTemperature, arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const override; + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE virtual void update( localIndex const k, localIndex const q, diff --git a/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.cpp b/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.cpp index 3364aab38e3..0ca3532f241 100644 --- a/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.cpp +++ b/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.cpp @@ -19,418 +19,211 @@ #include "common/Path.hpp" #include "constitutive/fluid/MultiFluidUtils.hpp" -#include "PVTFunctions/FlashModelBase.hpp" -#include "PVTFunctions/PVTFunctionBase.hpp" - +#include "constitutive/fluid/PVTFunctions/FlashModelBase.hpp" +#include "constitutive/fluid/PVTFunctions/PVTFunctionBase.hpp" +#include "constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp" namespace geosx { using namespace dataRepository; -using namespace PVTProps; namespace constitutive { -MultiPhaseMultiComponentFluid::MultiPhaseMultiComponentFluid( string const & name, Group * const parent ): - MultiFluidBase( name, parent ) +using namespace PVTProps; + +namespace +{ +template< typename P1DENS, typename P1VISC, typename P2DENS, typename P2VISC, typename FLASH > class + TwoPhaseCatalogNames {}; + +template<> class + TwoPhaseCatalogNames< PVTProps::BrineCO2Density, + PVTProps::BrineViscosity, + PVTProps::SpanWagnerCO2Density, + PVTProps::FenghourCO2Viscosity, + PVTProps::CO2Solubility > +{ +public: + static string name() { return "CO2BrineFluid"; } +}; +} // end namespace + +// provide a definition for catalogName() +template< typename P1DENS, typename P1VISC, typename P2DENS, typename P2VISC, typename FLASH > +string MultiPhaseMultiComponentFluid< P1DENS, P1VISC, P2DENS, P2VISC, FLASH >::catalogName() { + return TwoPhaseCatalogNames< P1DENS, P1VISC, P2DENS, P2VISC, FLASH >::name(); +} +template< typename P1DENS, typename P1VISC, typename P2DENS, typename P2VISC, typename FLASH > +MultiPhaseMultiComponentFluid< P1DENS, P1VISC, P2DENS, P2VISC, FLASH >:: +MultiPhaseMultiComponentFluid( string const & name, Group * const parent ): + MultiFluidBase( name, parent ) +{ registerWrapper( viewKeyStruct::phasePVTParaFilesString(), &m_phasePVTParaFiles ). setInputFlag( InputFlags::REQUIRED ). setRestartFlags( RestartFlags::NO_WRITE ). - setDescription( "List of the names of the files including PVT function parameters" ); + setDescription( "Names of the files defining the parameters of the viscosity and density models" ); registerWrapper( viewKeyStruct::flashModelParaFileString(), &m_flashModelParaFile ). setInputFlag( InputFlags::REQUIRED ). setRestartFlags( RestartFlags::NO_WRITE ). - setDescription( "name of the filen including flash calculation function parameters" ); - + setDescription( "Name of the file defining the parameters of the flash model" ); } -MultiPhaseMultiComponentFluid::~MultiPhaseMultiComponentFluid() -{} - - +template< typename P1DENS, typename P1VISC, typename P2DENS, typename P2VISC, typename FLASH > std::unique_ptr< ConstitutiveBase > -MultiPhaseMultiComponentFluid::deliverClone( string const & name, - Group * const parent ) const +MultiPhaseMultiComponentFluid< P1DENS, P1VISC, P2DENS, P2VISC, FLASH >:: +deliverClone( string const & name, Group * const parent ) const { std::unique_ptr< ConstitutiveBase > clone = MultiFluidBase::deliverClone( name, parent ); MultiPhaseMultiComponentFluid * const newConstitutiveRelation = dynamic_cast< MultiPhaseMultiComponentFluid * >(clone.get()); + newConstitutiveRelation->m_p1Index = this->m_p1Index; + newConstitutiveRelation->m_p2Index = this->m_p2Index; - - newConstitutiveRelation->m_useMass = this->m_useMass; - - newConstitutiveRelation->m_componentNames = this->m_componentNames; - newConstitutiveRelation->m_componentMolarWeight = this->m_componentMolarWeight; - - newConstitutiveRelation->m_phaseNames = this->m_phaseNames; - - newConstitutiveRelation->m_phasePVTParaFiles = this->m_phasePVTParaFiles; - - newConstitutiveRelation->m_flashModelParaFile = this->m_flashModelParaFile; - - // newConstitutiveRelation->CreatePVTModels(); - - newConstitutiveRelation->m_phaseDensityFuns = this->m_phaseDensityFuns; - newConstitutiveRelation->m_phaseViscosityFuns = this->m_phaseViscosityFuns; - - newConstitutiveRelation->m_flashModel = this->m_flashModel; + newConstitutiveRelation->createPVTModels(); return clone; } -void MultiPhaseMultiComponentFluid::postProcessInput() +template< typename P1DENS, typename P1VISC, typename P2DENS, typename P2VISC, typename FLASH > +void MultiPhaseMultiComponentFluid< P1DENS, P1VISC, P2DENS, P2VISC, FLASH >::postProcessInput() { MultiFluidBase::postProcessInput(); - localIndex const NP = numFluidPhases(); - - GEOSX_ERROR_IF( m_phasePVTParaFiles.size() != NP, "The number of phasePVTParaFiles is not the same as the number of phases!" ); + localIndex const numPhases = numFluidPhases(); + localIndex const numComps = numFluidComponents(); + GEOSX_THROW_IF( numPhases != 2, + "The number of phases in this model should be equal to 2", + InputError ); + GEOSX_THROW_IF( numComps != 2, + "The number of components in this model should be equal to 2", + InputError ); + GEOSX_THROW_IF( m_phasePVTParaFiles.size() != 2, + "The number of phasePVTParaFiles is not the same as the number of phases!", + InputError ); + + // NOTE: for now, the names of the phases are still hardcoded here + // Later, we could read them from the XML file and we would then have a general class here + + char const * expectedWaterPhaseNames[] = { "Water", "water", "Liquid", "liquid" }; + m_p1Index = PVTFunctionHelpers::findName( m_phaseNames, + expectedWaterPhaseNames ); + GEOSX_THROW_IF( m_p1Index < 0 || m_p1Index >= m_phaseNames.size(), + "Phase water/liquid is not found!", + InputError ); + + char const * expectedGasPhaseNames[] = { "CO2", "co2", "gas", "Gas" }; + m_p2Index = PVTFunctionHelpers::findName( m_phaseNames, + expectedGasPhaseNames ); + GEOSX_THROW_IF( m_p2Index < 0 || m_p2Index >= m_phaseNames.size(), + "Phase co2/gas is not found!", + InputError ); createPVTModels(); - } -void MultiPhaseMultiComponentFluid::initializePostSubGroups() +template< typename P1DENS, typename P1VISC, typename P2DENS, typename P2VISC, typename FLASH > +void MultiPhaseMultiComponentFluid< P1DENS, P1VISC, P2DENS, P2VISC, FLASH >::createPVTModels() { - MultiFluidBase::initializePostSubGroups(); - - // CreatePVTModels(); - -} - - -void MultiPhaseMultiComponentFluid::createPVTModels() -{ - for( string & filename : m_phasePVTParaFiles ) + // 1) Create the viscosity and density models + for( string const & filename : m_phasePVTParaFiles ) { std::ifstream is( filename ); - constexpr std::streamsize buf_size = 256; char buf[buf_size]; - while( is.getline( buf, buf_size )) + while( is.getline( buf, buf_size ) ) { string const str( buf ); string_array const strs = stringutilities::tokenize( str, " " ); if( strs[0] == "DensityFun" ) { - m_phaseDensityFuns.emplace_back( PVTFunction::CatalogInterface::factory( strs[ 1 ], - strs, - m_componentNames, - m_componentMolarWeight ) ); + if( strs[1] == P1DENS::catalogName() ) + { + m_p1Density = std::make_unique< P1DENS >( strs, m_componentNames, m_componentMolarWeight ); + m_p1DensityWrapper.emplace_back( m_p1Density->createKernelWrapper() ); + } + else if( strs[1] == P2DENS::catalogName() ) + { + m_p2Density = std::make_unique< P2DENS >( strs, m_componentNames, m_componentMolarWeight ); + m_p2DensityWrapper.emplace_back( m_p2Density->createKernelWrapper() ); + } } else if( strs[0] == "ViscosityFun" ) { - m_phaseViscosityFuns.emplace_back( PVTFunction::CatalogInterface::factory( strs[ 1 ], - strs, - m_componentNames, - m_componentMolarWeight ) ); + if( strs[1] == P1VISC::catalogName() ) + { + m_p1Viscosity = std::make_unique< P1VISC >( strs, m_componentNames, m_componentMolarWeight ); + m_p1ViscosityWrapper.emplace_back( m_p1Viscosity->createKernelWrapper() ); + } + else if( strs[1] == P2VISC::catalogName() ) + { + m_p2Viscosity = std::make_unique< P2VISC >( strs, m_componentNames, m_componentMolarWeight ); + m_p2ViscosityWrapper.emplace_back( m_p2Viscosity->createKernelWrapper() ); + } } else { - GEOSX_ERROR( "Error: Invalid PVT function: " << strs[0] << "." ); + GEOSX_THROW( "Error: Invalid PVT function: " << strs[0] << ".", InputError ); } } - is.close(); } + GEOSX_THROW_IF( m_p1Density == nullptr, + P1DENS::catalogName() << " model not found", + InputError ); + GEOSX_THROW_IF( m_p2Density == nullptr, + P2DENS::catalogName() << " model not found", + InputError ); + GEOSX_THROW_IF( m_p1Viscosity == nullptr, + P1VISC::catalogName() << " model not found", + InputError ); + GEOSX_THROW_IF( m_p2Viscosity == nullptr, + P2VISC::catalogName() << " model not found", + InputError ); + + // 2) Create the flash model { std::ifstream is( m_flashModelParaFile ); - constexpr std::streamsize buf_size = 256; char buf[buf_size]; - while( is.getline( buf, buf_size )) + while( is.getline( buf, buf_size ) ) { string const str( buf ); string_array const strs = stringutilities::tokenize( str, " " ); - - if( strs[0] == "FlashModel" ) + if( strs[0] == "FlashModel" && strs[1] == FLASH::catalogName() ) { - m_flashModel = FlashModel::CatalogInterface::factory( strs[1], - strs, - m_phaseNames, - m_componentNames, - m_componentMolarWeight ); + m_flash = std::make_unique< FLASH >( strs, m_phaseNames, m_componentNames, m_componentMolarWeight ); + m_flashWrapper.emplace_back( m_flash->createKernelWrapper() ); } else { - GEOSX_ERROR( "Error: Not flash model: " << strs[0] << "." ); + GEOSX_THROW( "Error: Invalid flash model: " << strs[0] << ", " << strs[1] << ".", InputError ); } } - is.close(); } -} -REGISTER_CATALOG_ENTRY( ConstitutiveBase, MultiPhaseMultiComponentFluid, string const &, Group * const ) - -void MultiPhaseMultiComponentFluidUpdate::compute( real64 pressure, - real64 temperature, - arraySlice1d< real64 const > const & composition, - arraySlice1d< real64 > const & phaseFraction, - arraySlice1d< real64 > const & phaseDensity, - arraySlice1d< real64 > const & phaseMassDensity, - arraySlice1d< real64 > const & phaseViscosity, - arraySlice2d< real64 > const & phaseCompFraction, - real64 & totalDensity ) const -{ - GEOSX_UNUSED_VAR( pressure ) - GEOSX_UNUSED_VAR( temperature ) - GEOSX_UNUSED_VAR( composition ) - GEOSX_UNUSED_VAR( phaseFraction ) - GEOSX_UNUSED_VAR( phaseDensity ) - GEOSX_UNUSED_VAR( phaseMassDensity ) - GEOSX_UNUSED_VAR( phaseViscosity ) - GEOSX_UNUSED_VAR( phaseCompFraction ) - GEOSX_UNUSED_VAR( totalDensity ) - GEOSX_ERROR( "Not implemented" ); + GEOSX_THROW_IF( m_flash == nullptr, + FLASH::catalogName() << " not found", + InputError ); } -void MultiPhaseMultiComponentFluidUpdate::compute( real64 pressure, - real64 temperature, - arraySlice1d< real64 const > const & composition, - arraySlice1d< real64 > const & phaseFraction, - arraySlice1d< real64 > const & dPhaseFraction_dPressure, - arraySlice1d< real64 > const & dPhaseFraction_dTemperature, - arraySlice2d< real64 > const & dPhaseFraction_dGlobalCompFraction, - arraySlice1d< real64 > const & phaseDensity, - arraySlice1d< real64 > const & dPhaseDensity_dPressure, - arraySlice1d< real64 > const & dPhaseDensity_dTemperature, - arraySlice2d< real64 > const & dPhaseDensity_dGlobalCompFraction, - arraySlice1d< real64 > const & phaseMassDensity, - arraySlice1d< real64 > const & dPhaseMassDensity_dPressure, - arraySlice1d< real64 > const & dPhaseMassDensity_dTemperature, - arraySlice2d< real64 > const & dPhaseMassDensity_dGlobalCompFraction, - arraySlice1d< real64 > const & phaseViscosity, - arraySlice1d< real64 > const & dPhaseViscosity_dPressure, - arraySlice1d< real64 > const & dPhaseViscosity_dTemperature, - arraySlice2d< real64 > const & dPhaseViscosity_dGlobalCompFraction, - arraySlice2d< real64 > const & phaseCompFraction, - arraySlice2d< real64 > const & dPhaseCompFraction_dPressure, - arraySlice2d< real64 > const & dPhaseCompFraction_dTemperature, - arraySlice3d< real64 > const & dPhaseCompFraction_dGlobalCompFraction, - real64 & totalDensity, - real64 & dTotalDensity_dPressure, - real64 & dTotalDensity_dTemperature, - arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const -{ - CompositionalVarContainer< 1 > phaseFrac { - phaseFraction, - dPhaseFraction_dPressure, - dPhaseFraction_dTemperature, - dPhaseFraction_dGlobalCompFraction - }; - - CompositionalVarContainer< 1 > phaseDens { - phaseDensity, - dPhaseDensity_dPressure, - dPhaseDensity_dTemperature, - dPhaseDensity_dGlobalCompFraction - }; - - CompositionalVarContainer< 1 > phaseMassDens { - phaseMassDensity, - dPhaseMassDensity_dPressure, - dPhaseMassDensity_dTemperature, - dPhaseMassDensity_dGlobalCompFraction - }; - - CompositionalVarContainer< 1 > phaseVisc { - phaseViscosity, - dPhaseViscosity_dPressure, - dPhaseViscosity_dTemperature, - dPhaseViscosity_dGlobalCompFraction - }; - - CompositionalVarContainer< 2 > phaseCompFrac { - phaseCompFraction, - dPhaseCompFraction_dPressure, - dPhaseCompFraction_dTemperature, - dPhaseCompFraction_dGlobalCompFraction - }; - - CompositionalVarContainer< 0 > totalDens { - totalDensity, - dTotalDensity_dPressure, - dTotalDensity_dTemperature, - dTotalDensity_dGlobalCompFraction - }; - -#if defined(__CUDACC__) - // For some reason nvcc thinks these aren't used. - GEOSX_UNUSED_VAR( phaseFrac, phaseDens, phaseMassDens, phaseVisc, phaseCompFrac, totalDens ); -#endif - - localIndex constexpr maxNumComp = MultiFluidBase::MAX_NUM_COMPONENTS; - localIndex constexpr maxNumPhase = MultiFluidBase::MAX_NUM_PHASES; - localIndex const NC = numComponents(); - localIndex const NP = numPhases(); - - stackArray1d< EvalVarArgs, maxNumComp > C( NC ); - - if( m_useMass ) - { - stackArray1d< EvalVarArgs, maxNumComp > X( NC ); - EvalVarArgs totalMolality = 0.0; - for( localIndex ic = 0; ic < NC; ++ic ) - { - X[ic].m_var = composition[ic]; - X[ic].m_der[ic+1] = 1.0; - - real64 const mwInv = 1.0 / m_componentMolarWeight[ic]; - C[ic] = X[ic] * mwInv; // this is molality (units of mole/mass) - totalMolality += C[ic]; - } - - for( localIndex ic = 0; ic < NC; ++ic ) - { - C[ic] /= totalMolality; - } - } - else - { - for( localIndex ic = 0; ic < NC; ++ic ) - { - C[ic].m_var = composition[ic]; - C[ic].m_der[ic+1] = 1.0; - } - } - - EvalVarArgs P = pressure; - P.m_der[0] = 1.0; - - constexpr real64 TK = 273.15; - EvalVarArgs T = temperature - TK; +// explicit instantiation of the model template; unfortunately we can't use CO2BrineFluid alias for this +template class MultiPhaseMultiComponentFluid< PVTProps::BrineCO2Density, + PVTProps::BrineViscosity, + PVTProps::SpanWagnerCO2Density, + PVTProps::FenghourCO2Viscosity, + PVTProps::CO2Solubility >; - stackArray1d< EvalVarArgs, maxNumPhase > phaseFractionTemp( NP ); - stackArray2d< EvalVarArgs, maxNumPhase * maxNumComp > phaseCompFractionTemp( NP, NC ); - - //phaseFractionTemp and phaseCompFractionTemp all are mole fraction, - //w.r.t mole fraction or mass fraction (useMass) - m_flashModel->partition( P, T, C, phaseFractionTemp, phaseCompFractionTemp ); - - stackArray1d< EvalVarArgs, maxNumPhase > phaseDensityTemp( NP ); - stackArray1d< EvalVarArgs, maxNumPhase > phaseMassDensityTemp( NP ); - stackArray1d< EvalVarArgs, maxNumPhase > phaseViscosityTemp( NP ); - - for( localIndex ip = 0; ip < NP; ++ip ) - { - // molarDensity or massDensity (useMass) - m_phaseDensityFuns[ip]->evaluation( P, T, phaseCompFractionTemp[ip], phaseDensityTemp[ip], m_useMass ); - m_phaseViscosityFuns[ip]->evaluation( P, T, phaseCompFractionTemp[ip], phaseViscosityTemp[ip] ); - } - - if( m_useMass ) - { - stackArray1d< EvalVarArgs, maxNumPhase > phaseMW( NP ); - for( localIndex ip = 0; ip < NP; ++ip ) - { - // copy phaseDens into phaseMassDens - phaseMassDensityTemp[ip] = phaseDensityTemp[ip]; - - // compute the molecular weight to get the mass phase (component) fractions - EvalVarArgs molarDens; - m_phaseDensityFuns[ip]->evaluation( P, T, phaseCompFractionTemp[ip], molarDens, 0 ); - phaseMW[ip] = phaseDensityTemp[ip] / molarDens; - } - - EvalVarArgs totalMass = 0.0; - for( localIndex ip = 0; ip < NP; ++ip ) - { - phaseFractionTemp[ip] *= phaseMW[ip]; - totalMass += phaseFractionTemp[ip]; - } - - for( localIndex ip = 0; ip < NP; ++ip ) - { - phaseFractionTemp[ip] /= totalMass; - } - - for( localIndex ip = 0; ip < NP; ++ip ) - { - for( localIndex ic = 0; ic < NC; ++ic ) - { - - real64 compMW = m_componentMolarWeight[ic]; - - phaseCompFractionTemp[ip][ic] = phaseCompFractionTemp[ip][ic] * compMW / phaseMW[ip]; - - } - } - } - else - { - for( localIndex ip = 0; ip < NP; ++ip ) - { - // recompute the mass density - EvalVarArgs massDens; - m_phaseDensityFuns[ip]->evaluation( P, T, phaseCompFractionTemp[ip], massDens, 1 ); - - // copy phaseDens into phaseMassDens - phaseMassDensityTemp[ip] = massDens; - } - } - - EvalVarArgs totalDensityTemp = 0.0; - for( localIndex ip = 0; ip < NP; ++ip ) - { - totalDensityTemp += phaseFractionTemp[ip] / phaseDensityTemp[ip]; - } - totalDensityTemp = 1.0 / totalDensityTemp; - - //transfer data - for( localIndex ip = 0; ip < NP; ++ip ) - { - phaseFrac.value[ip] = phaseFractionTemp[ip].m_var; - phaseFrac.dPres[ip] = phaseFractionTemp[ip].m_der[0]; - phaseFrac.dTemp[ip] = 0.0; - - phaseDens.value[ip] = phaseDensityTemp[ip].m_var; - phaseDens.dPres[ip] = phaseDensityTemp[ip].m_der[0]; - phaseDens.dTemp[ip] = 0.0; - - phaseMassDens.value[ip] = phaseMassDensityTemp[ip].m_var; - phaseMassDens.dPres[ip] = phaseMassDensityTemp[ip].m_der[0]; - phaseMassDens.dTemp[ip] = 0.0; - - phaseVisc.value[ip] = phaseViscosityTemp[ip].m_var; - phaseVisc.dPres[ip] = phaseViscosityTemp[ip].m_der[0]; - phaseVisc.dTemp[ip] = 0.0; - - for( localIndex ic = 0; ic < NC; ++ic ) - { - phaseFrac.dComp[ip][ic] = phaseFractionTemp[ip].m_der[ic+1]; - phaseDens.dComp[ip][ic] = phaseDensityTemp[ip].m_der[ic+1]; - phaseMassDens.dComp[ip][ic] = phaseMassDensityTemp[ip].m_der[ic+1]; - phaseVisc.dComp[ip][ic] = phaseViscosityTemp[ip].m_der[ic+1]; - - phaseCompFrac.value[ip][ic] = phaseCompFractionTemp[ip][ic].m_var; - phaseCompFrac.dPres[ip][ic] = phaseCompFractionTemp[ip][ic].m_der[0]; - phaseCompFrac.dTemp[ip][ic] = 0.0; - - for( localIndex jc = 0; jc < NC; ++jc ) - { - phaseCompFrac.dComp[ip][ic][jc] = phaseCompFractionTemp[ip][ic].m_der[jc+1]; - } - } - } - - totalDens.value = totalDensityTemp.m_var; - totalDens.dPres = totalDensityTemp.m_der[0]; - totalDens.dTemp = 0.0; - - for( localIndex ic = 0; ic < NC; ++ic ) - { - totalDens.dComp[ic] = totalDensityTemp.m_der[ic+1]; - } -} +REGISTER_CATALOG_ENTRY( ConstitutiveBase, CO2BrineFluid, string const &, Group * const ) } //namespace constitutive diff --git a/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.hpp b/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.hpp index f91e5c48830..7b27f0b3191 100644 --- a/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.hpp +++ b/src/coreComponents/constitutive/fluid/MultiPhaseMultiComponentFluid.hpp @@ -20,41 +20,36 @@ #define GEOSX_CONSTITUTIVE_FLUID_MULTIPHASEMULTICOMPONENTFLUID_HPP_ #include "constitutive/fluid/MultiFluidBase.hpp" +#include "constitutive/fluid/MultiFluidUtils.hpp" +#include "constitutive/fluid/PVTFunctions/BrineCO2Density.hpp" +#include "constitutive/fluid/PVTFunctions/BrineViscosity.hpp" +#include "constitutive/fluid/PVTFunctions/CO2Solubility.hpp" +#include "constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.hpp" +#include "constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.hpp" #include - namespace geosx { -namespace dataRepository -{ -namespace keys -{ -string const multiPhaseMultiComponentFluid = "MultiPhaseMultiComponentFluid"; -} -} - -namespace PVTProps -{ -class PVTFunction; -class FlashModel; -} - namespace constitutive { /** * @brief Kernel wrapper class for MultiPhaseMultiComponentFluid. - * @note Not thread-safe, do not use with any parallel launch policy. */ +template< typename P1DENSWRAPPER, typename P1VISCWRAPPER, typename P2DENSWRAPPER, typename P2VISCWRAPPER, typename FLASHWRAPPER > class MultiPhaseMultiComponentFluidUpdate final : public MultiFluidBaseUpdate { public: - MultiPhaseMultiComponentFluidUpdate( std::vector< std::shared_ptr< PVTProps::PVTFunction const > > const & phaseDensityFuns, - std::vector< std::shared_ptr< PVTProps::PVTFunction const > > const & phaseViscosityFuns, - std::shared_ptr< PVTProps::FlashModel const > const & flashModel, + MultiPhaseMultiComponentFluidUpdate( localIndex const p1Index, + localIndex const p2Index, + arrayView1d< P1DENSWRAPPER const > const & p1DensityWrapper, + arrayView1d< P1VISCWRAPPER const > const & p1ViscosityWrapper, + arrayView1d< P2DENSWRAPPER const > const & p2DensityWrapper, + arrayView1d< P2VISCWRAPPER const > const & p2ViscosityWrapper, + arrayView1d< FLASHWRAPPER const > const & flashWrapper, arrayView1d< real64 const > const & componentMolarWeight, bool useMass, arrayView3d< real64 > const & phaseFraction, @@ -107,9 +102,13 @@ class MultiPhaseMultiComponentFluidUpdate final : public MultiFluidBaseUpdate dTotalDensity_dPressure, dTotalDensity_dTemperature, dTotalDensity_dGlobalCompFraction ), - m_phaseDensityFuns( phaseDensityFuns ), - m_phaseViscosityFuns( phaseViscosityFuns ), - m_flashModel( flashModel ) + m_p1Index( p1Index ), + m_p2Index( p2Index ), + m_p1DensityWrapper( p1DensityWrapper ), + m_p1ViscosityWrapper( p1ViscosityWrapper ), + m_p2DensityWrapper( p2DensityWrapper ), + m_p2ViscosityWrapper( p2ViscosityWrapper ), + m_flashWrapper( flashWrapper ) {} /// Default copy constructor @@ -124,6 +123,8 @@ class MultiPhaseMultiComponentFluidUpdate final : public MultiFluidBaseUpdate /// Deleted move assignment operator MultiPhaseMultiComponentFluidUpdate & operator=( MultiPhaseMultiComponentFluidUpdate && ) = delete; + GEOSX_HOST_DEVICE + GEOSX_FORCE_INLINE virtual void compute( real64 const pressure, real64 const temperature, arraySlice1d< real64 const > const & composition, @@ -134,6 +135,8 @@ class MultiPhaseMultiComponentFluidUpdate final : public MultiFluidBaseUpdate arraySlice2d< real64 > const & phaseCompFraction, real64 & totalDensity ) const override; + GEOSX_HOST_DEVICE + GEOSX_FORCE_INLINE virtual void compute( real64 const pressure, real64 const temperature, arraySlice1d< real64 const > const & composition, @@ -162,6 +165,7 @@ class MultiPhaseMultiComponentFluidUpdate final : public MultiFluidBaseUpdate real64 & dTotalDensity_dTemperature, arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const override; + GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE virtual void update( localIndex const k, localIndex const q, @@ -200,31 +204,54 @@ class MultiPhaseMultiComponentFluidUpdate final : public MultiFluidBaseUpdate private: - std::vector< std::shared_ptr< PVTProps::PVTFunction const > > m_phaseDensityFuns; - std::vector< std::shared_ptr< PVTProps::PVTFunction const > > m_phaseViscosityFuns; - std::shared_ptr< PVTProps::FlashModel const > m_flashModel; + /// Index of the liquid phase + localIndex const m_p1Index; + /// Index of the gas phase + localIndex const m_p2Index; + + /// Kernel wrapper for brine density updates + arrayView1d< P1DENSWRAPPER const > const m_p1DensityWrapper; + + /// Kernel wrapper for brine viscosity updates + arrayView1d< P1VISCWRAPPER const > const m_p1ViscosityWrapper; + + /// Kernel wrapper for CO2 density updates + arrayView1d< P2DENSWRAPPER const > const m_p2DensityWrapper; + + /// Kernel wrapper for CO2 viscosity updates + arrayView1d< P2VISCWRAPPER const > const m_p2ViscosityWrapper; + + /// Kernel wrapper for phase fraction and phase component fraction updates + arrayView1d< FLASHWRAPPER const > const m_flashWrapper; }; +template< typename P1DENS, typename P1VISC, typename P2DENS, typename P2VISC, typename FLASH > class MultiPhaseMultiComponentFluid : public MultiFluidBase { public: + using exec_policy = parallelDevicePolicy<>; + MultiPhaseMultiComponentFluid( string const & name, Group * const parent ); - virtual ~MultiPhaseMultiComponentFluid() override; + virtual ~MultiPhaseMultiComponentFluid() override {}; virtual std::unique_ptr< ConstitutiveBase > deliverClone( string const & name, Group * const parent ) const override; - static string catalogName() { return dataRepository::keys::multiPhaseMultiComponentFluid; } + static string catalogName(); virtual string getCatalogName() const override { return catalogName(); } /// Type of kernel wrapper for in-kernel update - using KernelWrapper = MultiPhaseMultiComponentFluidUpdate; + using KernelWrapper = MultiPhaseMultiComponentFluidUpdate< typename P1DENS::KernelWrapper, + typename P1VISC::KernelWrapper, + typename P2DENS::KernelWrapper, + typename P2VISC::KernelWrapper, + typename FLASH::KernelWrapper >; /** * @brief Create an update kernel wrapper. @@ -232,9 +259,13 @@ class MultiPhaseMultiComponentFluid : public MultiFluidBase */ KernelWrapper createKernelWrapper() { - return KernelWrapper( m_phaseDensityFuns, - m_phaseViscosityFuns, - m_flashModel, + return KernelWrapper( m_p1Index, + m_p2Index, + m_p1DensityWrapper.toViewConst(), + m_p1ViscosityWrapper.toViewConst(), + m_p2DensityWrapper.toViewConst(), + m_p2ViscosityWrapper.toViewConst(), + m_flashWrapper.toViewConst(), m_componentMolarWeight.toViewConst(), m_useMass, m_phaseFraction, @@ -267,31 +298,612 @@ class MultiPhaseMultiComponentFluid : public MultiFluidBase { static constexpr char const * flashModelParaFileString() { return "flashModelParaFile"; } static constexpr char const * phasePVTParaFilesString() { return "phasePVTParaFiles"; } - }; - + } viewKeysMultiPhaseMultiComponentFluid; protected: - virtual void postProcessInput() override; - virtual void initializePostSubGroups() override; + virtual void postProcessInput() override; private: void createPVTModels(); - // phase PVT parameter filenames + /// Names of the files defining the viscosity and density models path_array m_phasePVTParaFiles; + /// Name of the file defining the flash model Path m_flashModelParaFile; - // number of entries corrosponds to number of phases - std::vector< std::shared_ptr< PVTProps::PVTFunction const > > m_phaseDensityFuns; - std::vector< std::shared_ptr< PVTProps::PVTFunction const > > m_phaseViscosityFuns; + /// Index of the liquid phase + localIndex m_p1Index; - std::shared_ptr< PVTProps::FlashModel const > m_flashModel; + /// Index of the gas phase + localIndex m_p2Index; + + /// Pointer to the brine density model + std::unique_ptr< P1DENS > m_p1Density; + + /// Pointer to the brine viscosity model + std::unique_ptr< P1VISC > m_p1Viscosity; + + /// Pointer to the CO2 density model + std::unique_ptr< P2DENS > m_p2Density; + + /// Pointer to the CO2 viscosity model + std::unique_ptr< P2VISC > m_p2Viscosity; + + /// Pointer to the flash model + std::unique_ptr< FLASH > m_flash; + + // Note: here is the reason why I am storing **arrays of** wrappers instead of just storing wrappers + + // - If I store the wrappers here and pass them to the update class, then the total size of kernel arguments + // exceeds 4 KB, which the upper limit allowed by the compiler. + // - To circumvent this problem, I store **arrays of** wrappers here, and then I can pass the arrayViews + // to the kernel. In that case, the total size of kernel arguments is much smaller, so everything works fine. + // This workaround is a little bit odd, because it forces us to keep these arrays of size 1 here... + + /// Pointer to the brine density model + array1d< typename P1DENS::KernelWrapper > m_p1DensityWrapper; + + /// Pointer to the brine viscosity model + array1d< typename P1VISC::KernelWrapper > m_p1ViscosityWrapper; + + /// Pointer to the CO2 density model + array1d< typename P2DENS::KernelWrapper > m_p2DensityWrapper; + + /// Pointer to the CO2 viscosity model + array1d< typename P2VISC::KernelWrapper > m_p2ViscosityWrapper; + + /// Pointer to the flash model + array1d< typename FLASH::KernelWrapper > m_flashWrapper; }; +// this alias will be useful in constitutive dispatch +using CO2BrineFluid = MultiPhaseMultiComponentFluid< PVTProps::BrineCO2Density, + PVTProps::BrineViscosity, + PVTProps::SpanWagnerCO2Density, + PVTProps::FenghourCO2Viscosity, + PVTProps::CO2Solubility >; + +template< typename P1DENSWRAPPER, typename P1VISCWRAPPER, typename P2DENSWRAPPER, typename P2VISCWRAPPER, typename FLASHWRAPPER > +GEOSX_HOST_DEVICE +GEOSX_FORCE_INLINE +void MultiPhaseMultiComponentFluidUpdate< P1DENSWRAPPER, P1VISCWRAPPER, P2DENSWRAPPER, P2VISCWRAPPER, FLASHWRAPPER >:: +compute( real64 pressure, + real64 temperature, + arraySlice1d< real64 const > const & composition, + arraySlice1d< real64 > const & phaseFraction, + arraySlice1d< real64 > const & phaseDensity, + arraySlice1d< real64 > const & phaseMassDensity, + arraySlice1d< real64 > const & phaseViscosity, + arraySlice2d< real64 > const & phaseCompFraction, + real64 & totalDensity ) const +{ + constexpr localIndex numComps = 2; + constexpr localIndex numPhases = 2; + localIndex const ip1 = m_p1Index; + localIndex const ip2 = m_p2Index; + + // for now, compute the derivatives and discard them + stackArray1d< real64, numPhases > dPhaseFrac_dPres( numPhases ); + stackArray1d< real64, numPhases > dPhaseFrac_dTemp( numPhases ); + stackArray2d< real64, numPhases *numComps > dPhaseFrac_dComp( numPhases, numComps ); + stackArray2d< real64, numPhases *numComps > dPhaseCompFrac_dPres( numPhases, numComps ); + stackArray2d< real64, numPhases *numComps > dPhaseCompFrac_dTemp( numPhases, numComps ); + stackArray3d< real64, numPhases *numComps *numComps > dPhaseCompFrac_dComp( numPhases, numComps, numComps ); + real64 dPhaseDens_dPres = 0.0; + real64 dPhaseDens_dTemp = 0.0; + stackArray1d< real64, numComps > dPhaseDens_dComp( numComps ); + real64 dPhaseMassDens_dPres = 0.0; + real64 dPhaseMassDens_dTemp = 0.0; + stackArray1d< real64, numComps > dPhaseMassDens_dComp( numComps ); + real64 dPhaseVisc_dPres = 0.0; + real64 dPhaseVisc_dTemp = 0.0; + stackArray1d< real64, numComps > dPhaseVisc_dComp( numComps ); + + // 1. Convert input mass fractions to mole fractions and keep derivatives + + stackArray1d< real64, numComps > compMoleFrac( numComps ); + if( m_useMass ) + { + real64 totalMolality = 0.0; + for( localIndex ic = 0; ic < numComps; ++ic ) + { + real64 const mwInv = 1.0 / m_componentMolarWeight[ic]; + compMoleFrac[ic] = composition[ic] * mwInv; // this is molality (units of mole/mass) + totalMolality += compMoleFrac[ic]; + } + + real64 const totalMolalityInv = 1.0 / totalMolality; + for( localIndex ic = 0; ic < numComps; ++ic ) + { + compMoleFrac[ic] *= totalMolalityInv; + } + } + else + { + for( localIndex ic = 0; ic < numComps; ++ic ) + { + compMoleFrac[ic] = composition[ic]; + } + } + + // 2. Compute phase fractions and phase component fractions + + real64 const temperatureInCelsius = temperature - 273.15; + m_flashWrapper[0].compute( pressure, + temperatureInCelsius, + compMoleFrac, + phaseFraction, dPhaseFrac_dPres, dPhaseFrac_dTemp, dPhaseFrac_dComp, + phaseCompFraction, dPhaseCompFrac_dPres, dPhaseCompFrac_dTemp, dPhaseCompFrac_dComp ); + + // 3. Compute phase densities and phase viscosities + + m_p1DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip1], dPhaseCompFrac_dPres[ip1], dPhaseCompFrac_dTemp[ip1], dPhaseCompFrac_dComp[ip1], + phaseDensity[ip1], dPhaseDens_dPres, dPhaseDens_dTemp, dPhaseDens_dComp, + m_useMass ); + m_p1ViscosityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip1], dPhaseCompFrac_dPres[ip1], dPhaseCompFrac_dTemp[ip1], dPhaseCompFrac_dComp[ip1], + phaseViscosity[ip1], dPhaseVisc_dPres, dPhaseVisc_dTemp, dPhaseVisc_dComp, + m_useMass ); + + m_p2DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip2], dPhaseCompFrac_dPres[ip2], dPhaseCompFrac_dTemp[ip2], dPhaseCompFrac_dComp[ip2], + phaseDensity[ip2], dPhaseDens_dPres, dPhaseDens_dTemp, dPhaseDens_dComp, + m_useMass ); + m_p2ViscosityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip2], dPhaseCompFrac_dPres[ip2], dPhaseCompFrac_dTemp[ip2], dPhaseCompFrac_dComp[ip2], + phaseViscosity[ip2], dPhaseVisc_dPres, dPhaseVisc_dTemp, dPhaseVisc_dComp, + m_useMass ); + + // 4. Depending on the m_useMass flag, convert to mass variables or simply compute mass density + + // TODO: for now the treatment of molar/mass density requires too many interpolations in the tables, it needs to be fixed + // we should modify the PVT functions so that they can return phaseMassDens, phaseDens, and phaseMW in one call + // TODO: extract the following piece of code and write a function that can be used here and in MultiFluidPVTPackageWrapper + + if( m_useMass ) + { + // 4.1. Convert phase fractions (requires two passes) + real64 totalMass{}; + + // 4.1.0. Compute the phase molecular weights (ultimately, get that from the PVT function) + real64 phaseMW[2]{}; + real64 phaseMolarDens = 0.0; + real64 dPhaseMolarDens_dPres = 0.0; + real64 dPhaseMolarDens_dTemp = 0.0; + stackArray1d< real64, numComps > dPhaseMolarDens_dComp( 2 ); + m_p1DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip1], dPhaseCompFrac_dPres[ip1], dPhaseCompFrac_dTemp[ip1], dPhaseCompFrac_dComp[ip1], + phaseMolarDens, dPhaseMolarDens_dPres, dPhaseMolarDens_dTemp, dPhaseMolarDens_dComp, + 0 ); + phaseMW[ip1] = phaseDensity[ip1] / phaseMolarDens; + + m_p2DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip2], dPhaseCompFrac_dPres[ip2], dPhaseCompFrac_dTemp[ip2], dPhaseCompFrac_dComp[ip2], + phaseMolarDens, dPhaseMolarDens_dPres, dPhaseMolarDens_dTemp, dPhaseMolarDens_dComp, + 0 ); + phaseMW[ip2] = phaseDensity[ip2] / phaseMolarDens; + + // 4.1.1. Compute mass of each phase and total mass (on a 1-mole basis) + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + phaseFraction[ip] *= phaseMW[ip]; + totalMass += phaseFraction[ip]; + } + // 4.1.2. Normalize to get mass fractions + real64 const totalMassInv = 1.0 / totalMass; + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + phaseFraction[ip] *= totalMassInv; + } + // 4.2. Convert phase compositions + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + real64 const phaseMWInv = 1.0 / phaseMW[ip]; + + for( localIndex ic = 0; ic < numComps; ++ic ) + { + real64 const compMW = m_componentMolarWeight[ic]; + phaseCompFraction[ip][ic] = phaseCompFraction[ip][ic] * compMW * phaseMWInv; + } + } + // 4.3 Copy the phase densities into the phase mass densities + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + phaseMassDensity[ip] = phaseDensity[ip]; + } + } + else + { + // for now, we have to compute the phase mass density here + m_p1DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip1], dPhaseCompFrac_dPres[ip1], + dPhaseCompFrac_dTemp[ip1], dPhaseCompFrac_dComp[ip1], + phaseMassDensity[ip1], dPhaseMassDens_dPres, + dPhaseMassDens_dTemp, dPhaseMassDens_dComp, + true ); + m_p2DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFraction[ip2], dPhaseCompFrac_dPres[ip2], + dPhaseCompFrac_dTemp[ip2], dPhaseCompFrac_dComp[ip2], + phaseMassDensity[ip2], dPhaseMassDens_dPres, + dPhaseMassDens_dTemp, dPhaseMassDens_dComp, + true ); + } + + // TODO: extract the following piece of code and write a function that can be used here and in MultiFluidPVTPackageWrapper + + // 5. Compute total fluid mass/molar density and derivatives + { + totalDensity = 0.0; + // 5.1. Sum mass/molar fraction/density ratio over all phases to get the inverse of density + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + real64 const densInv = 1.0 / phaseDensity[ip]; + real64 const value = phaseFraction[ip] * densInv; + totalDensity += value; + } + // 5.2. Invert the previous quantity to get actual density + totalDensity = 1.0 / totalDensity; + } +} + +template< typename P1DENSWRAPPER, typename P1VISCWRAPPER, typename P2DENSWRAPPER, typename P2VISCWRAPPER, typename FLASHWRAPPER > +GEOSX_HOST_DEVICE +GEOSX_FORCE_INLINE +void MultiPhaseMultiComponentFluidUpdate< P1DENSWRAPPER, P1VISCWRAPPER, P2DENSWRAPPER, P2VISCWRAPPER, FLASHWRAPPER >:: +compute( real64 pressure, + real64 temperature, + arraySlice1d< real64 const > const & composition, + arraySlice1d< real64 > const & phaseFraction, + arraySlice1d< real64 > const & dPhaseFraction_dPressure, + arraySlice1d< real64 > const & dPhaseFraction_dTemperature, + arraySlice2d< real64 > const & dPhaseFraction_dGlobalCompFraction, + arraySlice1d< real64 > const & phaseDensity, + arraySlice1d< real64 > const & dPhaseDensity_dPressure, + arraySlice1d< real64 > const & dPhaseDensity_dTemperature, + arraySlice2d< real64 > const & dPhaseDensity_dGlobalCompFraction, + arraySlice1d< real64 > const & phaseMassDensity, + arraySlice1d< real64 > const & dPhaseMassDensity_dPressure, + arraySlice1d< real64 > const & dPhaseMassDensity_dTemperature, + arraySlice2d< real64 > const & dPhaseMassDensity_dGlobalCompFraction, + arraySlice1d< real64 > const & phaseViscosity, + arraySlice1d< real64 > const & dPhaseViscosity_dPressure, + arraySlice1d< real64 > const & dPhaseViscosity_dTemperature, + arraySlice2d< real64 > const & dPhaseViscosity_dGlobalCompFraction, + arraySlice2d< real64 > const & phaseCompFraction, + arraySlice2d< real64 > const & dPhaseCompFraction_dPressure, + arraySlice2d< real64 > const & dPhaseCompFraction_dTemperature, + arraySlice3d< real64 > const & dPhaseCompFraction_dGlobalCompFraction, + real64 & totalDensity, + real64 & dTotalDensity_dPressure, + real64 & dTotalDensity_dTemperature, + arraySlice1d< real64 > const & dTotalDensity_dGlobalCompFraction ) const +{ + // 0. make shortcut structs to avoid long names (TODO maybe remove) + CompositionalVarContainer< 1 > phaseFrac { + phaseFraction, + dPhaseFraction_dPressure, + dPhaseFraction_dTemperature, + dPhaseFraction_dGlobalCompFraction + }; + + CompositionalVarContainer< 1 > phaseDens { + phaseDensity, + dPhaseDensity_dPressure, + dPhaseDensity_dTemperature, + dPhaseDensity_dGlobalCompFraction + }; + + CompositionalVarContainer< 1 > phaseMassDens { + phaseMassDensity, + dPhaseMassDensity_dPressure, + dPhaseMassDensity_dTemperature, + dPhaseMassDensity_dGlobalCompFraction + }; + + CompositionalVarContainer< 1 > phaseVisc { + phaseViscosity, + dPhaseViscosity_dPressure, + dPhaseViscosity_dTemperature, + dPhaseViscosity_dGlobalCompFraction + }; + + CompositionalVarContainer< 2 > phaseCompFrac { + phaseCompFraction, + dPhaseCompFraction_dPressure, + dPhaseCompFraction_dTemperature, + dPhaseCompFraction_dGlobalCompFraction + }; + + CompositionalVarContainer< 0 > totalDens { + totalDensity, + dTotalDensity_dPressure, + dTotalDensity_dTemperature, + dTotalDensity_dGlobalCompFraction + }; + +#if defined(__CUDACC__) + // For some reason nvcc thinks these aren't used. + GEOSX_UNUSED_VAR( phaseFrac, phaseDens, phaseMassDens, phaseVisc, phaseCompFrac, totalDens ); +#endif + + constexpr localIndex numComps = 2; + constexpr localIndex numPhases = 2; + localIndex const ip1 = m_p1Index; + localIndex const ip2 = m_p2Index; + + // 1. Convert input mass fractions to mole fractions and keep derivatives + + stackArray1d< real64, numComps > compMoleFrac( numComps ); + stackArray2d< real64, numComps *numComps > dCompMoleFrac_dCompMassFrac( numComps, numComps ); + + if( m_useMass ) + { + real64 totalMolality = 0.0; + for( localIndex ic = 0; ic < numComps; ++ic ) + { + real64 const mwInv = 1.0 / m_componentMolarWeight[ic]; + compMoleFrac[ic] = composition[ic] * mwInv; // this is molality (units of mole/mass) + dCompMoleFrac_dCompMassFrac[ic][ic] = mwInv; + totalMolality += compMoleFrac[ic]; + } + + real64 const totalMolalityInv = 1.0 / totalMolality; + for( localIndex ic = 0; ic < numComps; ++ic ) + { + compMoleFrac[ic] *= totalMolalityInv; + + for( localIndex jc = 0; jc < numComps; ++jc ) + { + dCompMoleFrac_dCompMassFrac[ic][jc] -= compMoleFrac[ic] / m_componentMolarWeight[jc]; + dCompMoleFrac_dCompMassFrac[ic][jc] *= totalMolalityInv; + } + } + } + else + { + for( localIndex ic = 0; ic < numComps; ++ic ) + { + compMoleFrac[ic] = composition[ic]; + } + } + + // 2. Compute phase fractions and phase component fractions + + real64 const temperatureInCelsius = temperature - 273.15; + m_flashWrapper[0].compute( pressure, + temperatureInCelsius, + compMoleFrac, + phaseFrac.value, phaseFrac.dPres, phaseFrac.dTemp, phaseFrac.dComp, + phaseCompFrac.value, phaseCompFrac.dPres, phaseCompFrac.dTemp, phaseCompFrac.dComp ); + + // 3. Compute phase densities and phase viscosities + + m_p1DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip1], phaseCompFrac.dPres[ip1], phaseCompFrac.dTemp[ip1], phaseCompFrac.dComp[ip1], + phaseDens.value[ip1], phaseDens.dPres[ip1], phaseDens.dTemp[ip1], phaseDens.dComp[ip1], + m_useMass ); + m_p1ViscosityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip1], phaseCompFrac.dPres[ip1], phaseCompFrac.dTemp[ip1], phaseCompFrac.dComp[ip1], + phaseVisc.value[ip1], phaseVisc.dPres[ip1], phaseVisc.dTemp[ip1], phaseVisc.dComp[ip1], + m_useMass ); + m_p2DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip2], phaseCompFrac.dPres[ip2], phaseCompFrac.dTemp[ip2], phaseCompFrac.dComp[ip2], + phaseDens.value[ip2], phaseDens.dPres[ip2], phaseDens.dTemp[ip2], phaseDens.dComp[ip2], + m_useMass ); + m_p2ViscosityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip2], phaseCompFrac.dPres[ip2], phaseCompFrac.dTemp[ip2], phaseCompFrac.dComp[ip2], + phaseVisc.value[ip2], phaseVisc.dPres[ip2], phaseVisc.dTemp[ip2], phaseVisc.dComp[ip2], + m_useMass ); + + // 4. Depending on the m_useMass flag, convert to mass variables or simply compute mass density + + // TODO: for now the treatment of molar/mass density requires too many interpolations in the tables, it needs to be fixed + // we should modify the PVT functions so that they can return phaseMassDens, phaseDens, and phaseMW in one call + // TODO: extract the following piece of code and write a function that can be used here and in MultiFluidPVTPackageWrapper + + if( m_useMass ) + { + // 4.1. Convert phase fractions (requires two passes) + real64 totalMass{}; + real64 dTotalMass_dP{}; + real64 dTotalMass_dT{}; + real64 dTotalMass_dC[2]{}; + + // 4.1.0. Compute the phase molecular weights (ultimately, get that from the PVT function) + real64 phaseMW[2]{}; + real64 dPhaseMW_dPres[2]{}; + real64 dPhaseMW_dTemp[2]{}; + real64 dPhaseMW_dComp[2][2]{}; + real64 phaseMolarDens = 0.0; + real64 dPhaseMolarDens_dPres = 0.0; + real64 dPhaseMolarDens_dTemp = 0.0; + stackArray1d< real64, numComps > dPhaseMolarDens_dComp( 2 ); + m_p2DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip2], phaseCompFrac.dPres[ip2], phaseCompFrac.dTemp[ip2], phaseCompFrac.dComp[ip2], + phaseMolarDens, dPhaseMolarDens_dPres, dPhaseMolarDens_dTemp, dPhaseMolarDens_dComp, + 0 ); + phaseMW[ip2] = phaseDens.value[ip2] / phaseMolarDens; + dPhaseMW_dPres[ip2] = phaseDens.dPres[ip2] / phaseMolarDens - phaseMW[ip2]*dPhaseMolarDens_dPres / phaseMolarDens; + dPhaseMW_dTemp[ip2] = phaseDens.dTemp[ip2] / phaseMolarDens - phaseMW[ip2]*dPhaseMolarDens_dTemp / phaseMolarDens; + for( localIndex ic = 0; ic < numComps; ++ic ) + { + dPhaseMW_dComp[ip2][ic] = phaseDens.dComp[ip2][ic] / phaseMolarDens - phaseMW[ip2]*dPhaseMolarDens_dComp[ic] / phaseMolarDens; + } + m_p1DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip1], phaseCompFrac.dPres[ip1], phaseCompFrac.dTemp[ip1], phaseCompFrac.dComp[ip1], + phaseMolarDens, dPhaseMolarDens_dPres, dPhaseMolarDens_dTemp, dPhaseMolarDens_dComp, + 0 ); + phaseMW[ip1] = phaseDens.value[ip1] / phaseMolarDens; + dPhaseMW_dPres[ip1] = phaseDens.dPres[ip1] / phaseMolarDens - phaseMW[ip1]*dPhaseMolarDens_dPres / phaseMolarDens; + dPhaseMW_dTemp[ip1] = phaseDens.dTemp[ip1] / phaseMolarDens - phaseMW[ip1]*dPhaseMolarDens_dTemp / phaseMolarDens; + for( localIndex ic = 0; ic < numComps; ++ic ) + { + dPhaseMW_dComp[ip1][ic] = phaseDens.dComp[ip1][ic] / phaseMolarDens - phaseMW[ip1]*dPhaseMolarDens_dComp[ic]/phaseMolarDens; + } + + + // 4.1.1. Compute mass of each phase and total mass (on a 1-mole basis) + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + real64 const nu = phaseFrac.value[ip]; + + phaseFrac.value[ip] *= phaseMW[ip]; + phaseFrac.dPres[ip] = phaseFrac.dPres[ip] * phaseMW[ip] + nu * dPhaseMW_dPres[ip]; + phaseFrac.dTemp[ip] = phaseFrac.dTemp[ip] * phaseMW[ip] + nu * dPhaseMW_dTemp[ip]; + + totalMass += phaseFrac.value[ip]; + dTotalMass_dP += phaseFrac.dPres[ip]; + dTotalMass_dT += phaseFrac.dTemp[ip]; + + for( localIndex jc = 0; jc < numComps; ++jc ) + { + phaseFrac.dComp[ip][jc] = phaseFrac.dComp[ip][jc] * phaseMW[ip] + nu * dPhaseMW_dComp[ip][jc]; + dTotalMass_dC[jc] += phaseFrac.dComp[ip][jc]; + } + } + + // 4.1.2. Normalize to get mass fractions + real64 const totalMassInv = 1.0 / totalMass; + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + phaseFrac.value[ip] *= totalMassInv; + phaseFrac.dPres[ip] = ( phaseFrac.dPres[ip] - phaseFrac.value[ip] * dTotalMass_dP ) * totalMassInv; + phaseFrac.dTemp[ip] = ( phaseFrac.dTemp[ip] - phaseFrac.value[ip] * dTotalMass_dT ) * totalMassInv; + + for( localIndex jc = 0; jc < numComps; ++jc ) + { + phaseFrac.dComp[ip][jc] = ( phaseFrac.dComp[ip][jc] - phaseFrac.value[ip] * dTotalMass_dC[jc] ) * totalMassInv; + } + } + + // 4.2. Convert phase compositions + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + real64 const phaseMWInv = 1.0 / phaseMW[ip]; + + for( localIndex ic = 0; ic < numComps; ++ic ) + { + + real64 const compMW = m_componentMolarWeight[ic]; + + phaseCompFrac.value[ip][ic] = phaseCompFrac.value[ip][ic] * compMW * phaseMWInv; + phaseCompFrac.dPres[ip][ic] = + ( phaseCompFrac.dPres[ip][ic] * compMW - phaseCompFrac.value[ip][ic] * dPhaseMW_dPres[ip] ) * phaseMWInv; + phaseCompFrac.dTemp[ip][ic] = + ( phaseCompFrac.dTemp[ip][ic] * compMW - phaseCompFrac.value[ip][ic] * dPhaseMW_dTemp[ip] ) * phaseMWInv; + + for( localIndex jc = 0; jc < numComps; ++jc ) + { + phaseCompFrac.dComp[ip][ic][jc] = + ( phaseCompFrac.dComp[ip][ic][jc] * compMW - phaseCompFrac.value[ip][ic] * dPhaseMW_dComp[ip][jc] ) * phaseMWInv; + } + } + } + + // 4.3. Update derivatives w.r.t. mole fractions to derivatives w.r.t mass fractions + real64 work[numComps]{}; + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + applyChainRuleInPlace( numComps, dCompMoleFrac_dCompMassFrac, phaseFrac.dComp[ip], work ); + applyChainRuleInPlace( numComps, dCompMoleFrac_dCompMassFrac, phaseDens.dComp[ip], work ); + + for( localIndex ic = 0; ic < numComps; ++ic ) + { + applyChainRuleInPlace( numComps, dCompMoleFrac_dCompMassFrac, phaseCompFrac.dComp[ip][ic], work ); + } + } + + // 4.4 Copy the phase densities into the phase mass densities + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + phaseMassDens.value[ip] = phaseDens.value[ip]; + phaseMassDens.dPres[ip] = phaseDens.dPres[ip]; + phaseMassDens.dTemp[ip] = phaseDens.dTemp[ip]; + for( localIndex ic = 0; ic < numComps; ++ic ) + { + phaseMassDens.dComp[ip][ic] = phaseDens.dComp[ip][ic]; + } + } + } + else + { + // for now, we have to compute the phase mass density here + m_p1DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip1], phaseCompFrac.dPres[ip1], + phaseCompFrac.dTemp[ip1], phaseCompFrac.dComp[ip1], + phaseMassDens.value[ip1], phaseMassDens.dPres[ip1], + phaseMassDens.dTemp[ip1], phaseMassDens.dComp[ip1], + true ); + m_p2DensityWrapper[0].compute( pressure, + temperatureInCelsius, + phaseCompFrac.value[ip2], phaseCompFrac.dPres[ip2], + phaseCompFrac.dTemp[ip2], phaseCompFrac.dComp[ip2], + phaseMassDens.value[ip2], phaseMassDens.dPres[ip2], + phaseMassDens.dTemp[ip2], phaseMassDens.dComp[ip2], + true ); + } + + // TODO: extract the following piece of code and write a function that can be used here and in MultiFluidPVTPackageWrapper + + // 5. Compute total fluid mass/molar density and derivatives + { + totalDens.value = 0.0; + totalDens.dPres = 0.0; + totalDens.dTemp = 0.0; + for( localIndex jc = 0; jc < numComps; ++jc ) + { + totalDens.dComp[jc] = 0.0; + } + + // 5.1. Sum mass/molar fraction/density ratio over all phases to get the inverse of density + for( localIndex ip = 0; ip < numPhases; ++ip ) + { + real64 const densInv = 1.0 / phaseDens.value[ip]; + real64 const value = phaseFrac.value[ip] * densInv; + + totalDens.value += value; + totalDens.dPres += ( phaseFrac.dPres[ip] - value * phaseDens.dPres[ip] ) * densInv; + totalDens.dTemp += ( phaseFrac.dTemp[ip] - value * phaseDens.dTemp[ip] ) * densInv; + + for( localIndex jc = 0; jc < numComps; ++jc ) + { + totalDens.dComp[jc] += ( phaseFrac.dComp[ip][jc] - value * phaseDens.dComp[ip][jc] ) * densInv; + } + } + + // 5.2. Invert the previous quantity to get actual density + totalDens.value = 1.0 / totalDens.value; + real64 const minusDens2 = -totalDens.value * totalDens.value; + totalDens.dPres *= minusDens2; + totalDens.dTemp *= minusDens2; + + for( localIndex jc = 0; jc < numComps; ++jc ) + { + totalDens.dComp[jc] *= minusDens2; + } + } +} + } //namespace constitutive } //namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2Density.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2Density.cpp new file mode 100644 index 00000000000..f0b6bccc3ee --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2Density.cpp @@ -0,0 +1,140 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file BrineCO2Density.cpp + */ + +#include "constitutive/fluid/PVTFunctions/BrineCO2Density.hpp" + +#include "managers/Functions/FunctionManager.hpp" +#include "managers/GeosxState.hpp" + +namespace geosx +{ + +using namespace stringutilities; + +namespace constitutive +{ + +namespace PVTProps +{ + +BrineCO2Density::BrineCO2Density( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ): + PVTFunctionBase( inputPara[1], + componentNames, + componentMolarWeight ) +{ + char const * expectedCO2ComponentNames[] = { "CO2", "co2" }; + m_CO2Index = PVTFunctionHelpers::findName( componentNames, expectedCO2ComponentNames ); + GEOSX_THROW_IF( m_CO2Index < 0 || m_CO2Index >= componentNames.size(), + "Component CO2 is not found!", + InputError ); + + char const * expectedWaterComponentNames[] = { "Water", "water" }; + m_waterIndex = PVTFunctionHelpers::findName( componentNames, expectedWaterComponentNames ); + GEOSX_THROW_IF( m_waterIndex < 0 || m_waterIndex >= componentNames.size(), + "Component Water/Brine is not found!", + InputError ); + + makeTable( inputPara ); +} + +void BrineCO2Density::makeTable( string_array const & inputPara ) +{ + // initialize the (p,T) coordinates + PTTableCoordinates tableCoords; + PVTFunctionHelpers::initializePropertyTable( inputPara, tableCoords ); + + // initialize salinity + GEOSX_THROW_IF( inputPara.size() < 9, + "Invalid property input!", + InputError ); + real64 salinity = 0.0; + try + { + salinity = stod( inputPara[8] ); + } + catch( const std::invalid_argument & e ) + { + GEOSX_THROW( "Invalid property argument:" + string( e.what()), + InputError ); + } + + array1d< real64 > densities( tableCoords.nPressures() * tableCoords.nTemperatures() ); + calculateBrineDensity( tableCoords, salinity, densities ); + + FunctionManager & functionManager = getGlobalState().getFunctionManager(); + m_brineDensityTable = dynamicCast< TableFunction * >( functionManager.createChild( "TableFunction", "brineDensityTable" ) ); + m_brineDensityTable->setTableCoordinates( tableCoords.getCoords() ); + m_brineDensityTable->setTableValues( densities ); + m_brineDensityTable->reInitializeFunction(); + m_brineDensityTable->setInterpolationMethod( TableFunction::InterpolationType::Linear ); +} + +void BrineCO2Density::calculateBrineDensity( PTTableCoordinates const & tableCoords, + real64 const & salinity, + array1d< real64 > const & densities ) +{ + // these coefficients come from Phillips et al. (1981), equations (4) and (5), pages 14 and 15 + constexpr real64 c1 = -9.9595; + constexpr real64 c2 = 7.0845; + constexpr real64 c3 = 3.9093; + + constexpr real64 a1 = -0.004539; + constexpr real64 a2 = -0.0001638; + constexpr real64 a3 = 0.00002551; + + constexpr real64 AA = -3.033405; + constexpr real64 BB = 10.128163; + constexpr real64 CC = -8.750567; + constexpr real64 DD = 2.663107; + + localIndex const nPressures = tableCoords.nPressures(); + localIndex const nTemperatures = tableCoords.nTemperatures(); + + for( localIndex i = 0; i < nPressures; ++i ) + { + real64 const P = tableCoords.getPressure( i ) / 1e5; + + for( localIndex j = 0; j < nTemperatures; ++j ) + { + // see Phillips et al. (1981), equations (4) and (5), pages 14 and 15 + real64 const x = c1 * exp( a1 * salinity ) + + c2 * exp( a2 * tableCoords.getTemperature( j ) ) + + c3 * exp( a3 * P ); + densities[j*nPressures+i] = (AA + BB * x + CC * x * x + DD * x * x * x) * 1000.0; + } + } +} + +BrineCO2Density::KernelWrapper BrineCO2Density::createKernelWrapper() +{ + return KernelWrapper( m_componentNames, + m_componentMolarWeight, + m_brineDensityTable, + m_CO2Index, + m_waterIndex ); +} + +REGISTER_CATALOG_ENTRY( PVTFunctionBase, BrineCO2Density, string_array const &, string_array const &, array1d< real64 > const & ) + +} // namespace PVTProps + +} // namespace constitutive + +} // namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2Density.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2Density.hpp new file mode 100644 index 00000000000..81ac0819dcc --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2Density.hpp @@ -0,0 +1,245 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file BrineCO2Density.hpp + */ + +#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINECO2DENSITY_HPP_ +#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINECO2DENSITY_HPP_ + +#include "PVTFunctionBase.hpp" + +#include "constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp" +#include "managers/Functions/TableFunction.hpp" + +namespace geosx +{ + +namespace constitutive +{ + +namespace PVTProps +{ + +class BrineCO2DensityUpdate final : public PVTFunctionBaseUpdate +{ +public: + + BrineCO2DensityUpdate( arrayView1d< string const > const & componentNames, + arrayView1d< real64 const > const & componentMolarWeight, + TableFunction * brineDensityTable, + localIndex const CO2Index, + localIndex const waterIndex ) + : PVTFunctionBaseUpdate( componentNames, + componentMolarWeight ), + m_brineDensityTable( brineDensityTable->createKernelWrapper() ), + m_CO2Index( CO2Index ), + m_waterIndex( waterIndex ) + {} + + /// Default copy constructor + BrineCO2DensityUpdate( BrineCO2DensityUpdate const & ) = default; + + /// Default move constructor + BrineCO2DensityUpdate( BrineCO2DensityUpdate && ) = default; + + /// Deleted copy assignment operator + BrineCO2DensityUpdate & operator=( BrineCO2DensityUpdate const & ) = delete; + + /// Deleted move assignment operator + BrineCO2DensityUpdate & operator=( BrineCO2DensityUpdate && ) = delete; + + GEOSX_HOST_DEVICE + GEOSX_FORCE_INLINE + virtual void compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass = 0 ) const override; + +protected: + + /// Table with brine density tabulated as a function (P,T,sal) + TableFunction::KernelWrapper const m_brineDensityTable; + + /// Index of the CO2 component + localIndex const m_CO2Index; + + /// Index of the water component + localIndex const m_waterIndex; + +}; + +class BrineCO2Density : public PVTFunctionBase +{ +public: + + BrineCO2Density( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ); + + ~BrineCO2Density() override {} + + static string catalogName() { return "BrineCO2Density"; } + + virtual string getCatalogName() const override final { return catalogName(); } + + virtual PVTFunctionType functionType() const override + { + return PVTFunctionType::DENSITY; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = BrineCO2DensityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper(); + + +private: + + void makeTable( string_array const & inputPara ); + + void calculateBrineDensity( PVTProps::PTTableCoordinates const & tableCoords, + real64 const & salinity, + array1d< real64 > const & densities ); + + /// Table with brine density tabulated as a function of (P,T,sal) + TableFunction * m_brineDensityTable; + + /// Index of the CO2 phase + localIndex m_CO2Index; + + /// Index of the water phase + localIndex m_waterIndex; + +}; + +GEOSX_HOST_DEVICE +GEOSX_FORCE_INLINE +void BrineCO2DensityUpdate::compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass ) const +{ + // this method implements the method proposed by E. Garcia (2001) + + // these coefficients come from equation (2) from Garcia (2001) + constexpr real64 a = 37.51; + constexpr real64 b = -9.585e-2; + constexpr real64 c = 8.740e-4; + constexpr real64 d = -5.044e-7; + + real64 const input[2] = { pressure, temperature }; + real64 density = 0.0; + real64 densityDeriv[2]{}; + m_brineDensityTable.compute( input, density, densityDeriv ); + + // equation (2) from Garcia (2001) + real64 const squaredTemp = temperature * temperature; + real64 const V = ( a + + b * temperature + + c * squaredTemp + + d * squaredTemp * temperature ) * 1e-6; + real64 const dV_dTemp = ( b + + 2 * c * temperature + + 3 * d * squaredTemp ) * 1e-6; + + // CO2 concentration + real64 const wMwInv = 1.0 / m_componentMolarWeight[m_waterIndex]; + real64 const oneMinusCO2PhaseCompInv = 1.0 / ( 1.0 - phaseComposition[m_CO2Index] ); + real64 const oneMinusCO2PhaseCompInvSquared = oneMinusCO2PhaseCompInv * oneMinusCO2PhaseCompInv; + real64 const coef = wMwInv * phaseComposition[m_CO2Index] * oneMinusCO2PhaseCompInv; + real64 const dCoef_dPres = wMwInv * dPhaseComposition_dPressure[m_CO2Index] * oneMinusCO2PhaseCompInvSquared; + real64 const dCoef_dTemp = wMwInv * dPhaseComposition_dTemperature[m_CO2Index] * oneMinusCO2PhaseCompInvSquared; + real64 dCoef_dComp[2]{}; + dCoef_dComp[m_CO2Index] = wMwInv * dPhaseComposition_dGlobalCompFraction[m_CO2Index][m_CO2Index] * oneMinusCO2PhaseCompInvSquared; + dCoef_dComp[m_waterIndex] = wMwInv * dPhaseComposition_dGlobalCompFraction[m_CO2Index][m_waterIndex] * oneMinusCO2PhaseCompInvSquared; + + real64 const conc = coef * density; + real64 const dConc_dPres = dCoef_dPres * density + coef * densityDeriv[0]; + real64 const dConc_dTemp = dCoef_dTemp * density + coef * densityDeriv[1]; + real64 dConc_dComp[2]{}; + dConc_dComp[m_CO2Index] = dCoef_dComp[m_CO2Index] * density; + dConc_dComp[m_waterIndex] = dCoef_dComp[m_waterIndex] * density; + + // CO2 concentration times density times vol + real64 const concDensVol = conc * density * V; + real64 const dConcDensVol_dPres = ( dConc_dPres * density + conc * densityDeriv[0] ) * V; + real64 const dConcDensVol_dTemp = ( dConc_dTemp * density + conc * densityDeriv[1] ) * V + + conc * density * dV_dTemp; + real64 dConcDensVol_dComp[2]{}; + dConcDensVol_dComp[m_CO2Index] = dConc_dComp[m_CO2Index] * density * V; + dConcDensVol_dComp[m_waterIndex] = dConc_dComp[m_waterIndex] * density * V; + + // Brine density + // equation (1) from Garcia (2001) + if( useMass ) + { + value = density + + m_componentMolarWeight[m_CO2Index] * conc + - concDensVol; + dValue_dPressure = densityDeriv[0] + + m_componentMolarWeight[m_CO2Index] * dConc_dPres + - dConcDensVol_dPres; + dValue_dTemperature = densityDeriv[1] + + m_componentMolarWeight[m_CO2Index] * dConc_dTemp + - dConcDensVol_dTemp; + dValue_dGlobalCompFraction[m_CO2Index] = m_componentMolarWeight[m_CO2Index] * dConc_dComp[m_CO2Index] + - dConcDensVol_dComp[m_CO2Index]; + dValue_dGlobalCompFraction[m_waterIndex] = m_componentMolarWeight[m_CO2Index] * dConc_dComp[m_waterIndex] + - dConcDensVol_dComp[m_waterIndex]; + } + else + { + value = density / m_componentMolarWeight[m_waterIndex] + + conc + - concDensVol / m_componentMolarWeight[m_waterIndex]; + dValue_dPressure = densityDeriv[0] / m_componentMolarWeight[m_waterIndex] + + dConc_dPres + - dConcDensVol_dPres / m_componentMolarWeight[m_waterIndex]; + dValue_dTemperature = densityDeriv[1] / m_componentMolarWeight[m_waterIndex] + + dConc_dTemp + - dConcDensVol_dTemp / m_componentMolarWeight[m_waterIndex]; + dValue_dGlobalCompFraction[m_CO2Index] = dConc_dComp[m_CO2Index] + - dConcDensVol_dComp[m_CO2Index] / m_componentMolarWeight[m_waterIndex]; + dValue_dGlobalCompFraction[m_waterIndex] = dConc_dComp[m_waterIndex] + - dConcDensVol_dComp[m_waterIndex] / m_componentMolarWeight[m_waterIndex]; + } +} + +} // end namespace PVTProps + +} // end namespace constitutive + +} // end namespace geosx + +#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINECO2DENSITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2DensityFunction.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2DensityFunction.cpp deleted file mode 100644 index 911e40eea4d..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2DensityFunction.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file BrineCO2DensityFunction.cpp - */ - -#include "constitutive/fluid/PVTFunctions/BrineCO2DensityFunction.hpp" - -namespace geosx -{ - -using namespace stringutilities; - -namespace PVTProps -{ - -BrineCO2DensityFunction::BrineCO2DensityFunction( string_array const & inputPara, - string_array const & componentNames, - real64_array const & componentMolarWeight ): - PVTFunction( inputPara[1], componentNames, componentMolarWeight ) -{ - bool notFound = 1; - - for( localIndex i = 0; i < componentNames.size(); ++i ) - { - - if( componentNames[i] == "CO2" || componentNames[i] == "co2" ) - { - m_CO2Index = i; - notFound = 0; - break; - } - - } - - GEOSX_ERROR_IF( notFound, "Component CO2 is not found!" ); - - notFound = 1; - - for( localIndex i = 0; i < componentNames.size(); ++i ) - { - - if( componentNames[i] =="Water" || componentNames[i] == "water" ) - { - m_waterIndex = i; - notFound = 0; - break; - } - - } - - GEOSX_ERROR_IF( notFound, "Component Water/Brine is not found!" ); - - - makeTable( inputPara ); -} - -void BrineCO2DensityFunction::makeTable( string_array const & inputPara ) -{ - real64_array pressures; - real64_array temperatures; - - real64 PStart, PEnd, dP; - real64 TStart, TEnd, dT; - real64 P, T, m; - - dT = -1.0; - dP = -1.0; - TStart = -1.0; - TEnd = -1.0; - PStart = -1.0; - PEnd = -1.0; - - - GEOSX_ERROR_IF( inputPara.size() < 9, "Invalid BrineCO2Density input!" ); - - try - { - - PStart = stod( inputPara[2] ); - PEnd = stod( inputPara[3] ); - dP = stod( inputPara[4] ); - - TStart = stod( inputPara[5] ); - TEnd = stod( inputPara[6] ); - dT = stod( inputPara[7] ); - - m = stod( inputPara[8] ); - - } - catch( const std::invalid_argument & e ) - { - - GEOSX_ERROR( "Invalid BrineCO2Density argument:" + string( e.what())); - - } - - P = PStart; - - while( P <= PEnd ) - { - - pressures.emplace_back( P ); - P += dP; - - } - - T = TStart; - - while( T <= TEnd ) - { - - temperatures.emplace_back( T ); - T += dT; - - } - - localIndex const nP = pressures.size(); - localIndex const nT = temperatures.size(); - - real64_array2d densities( nP, nT ); - - calculateBrineDensity( pressures, temperatures, m, densities ); - - m_BrineDensityTable = std::make_shared< XYTable >( "BrineDensityTable", pressures, temperatures, densities ); -} - - -void BrineCO2DensityFunction::evaluation( EvalVarArgs const & pressure, EvalVarArgs const & temperature, - arraySlice1d< EvalVarArgs const > const & phaseComposition, EvalVarArgs & value, bool useMass ) const -{ - EvalArgs2D P, T, density; - P.m_var = pressure.m_var; - P.m_der[0] = 1.0; - - T.m_var = temperature.m_var; - T.m_der[1] = 1.0; - - density = m_BrineDensityTable->value( P, T ); - - constexpr real64 a = 37.51; - constexpr real64 b = -9.585e-2; - constexpr real64 c = 8.740e-4; - constexpr real64 d = -5.044e-7; - - real64 temp = T.m_var; - - real64 const V = (a + b * temp + c * temp * temp + d * temp * temp * temp) * 1e-6; - - real64 const CO2MW = m_componentMolarWeight[m_CO2Index]; - real64 const waterMW = m_componentMolarWeight[m_waterIndex]; - - EvalVarArgs den, C, X; - - den.m_var = density.m_var; - den.m_der[0] = density.m_der[0]; - - X = phaseComposition[m_CO2Index]; - - C = X * den / (waterMW * (1.0 - X)); - - if( useMass ) - { - value = den + CO2MW * C - C * den * V; - } - else - { - value = den / waterMW + C - C * den * V / waterMW; - } -} - -void BrineCO2DensityFunction::calculateBrineDensity( real64_array const & pressure, real64_array const & temperature, real64 const & salinity, - real64_array2d const & density ) -{ - constexpr real64 c1 = -9.9595; - constexpr real64 c2 = 7.0845; - constexpr real64 c3 = 3.9093; - - constexpr real64 a1 = -0.004539; - constexpr real64 a2 = -0.0001638; - constexpr real64 a3 = 0.00002551; - - constexpr real64 AA = -3.033405; - constexpr real64 BB = 10.128163; - constexpr real64 CC = -8.750567; - constexpr real64 DD = 2.663107; - - real64 P, x; - - for( localIndex i = 0; i < pressure.size(); ++i ) - { - - P = pressure[i] / 1e5; - - for( localIndex j = 0; j < temperature.size(); ++j ) - { - x = c1 * exp( a1 * salinity ) + c2 * exp( a2 * temperature[j] ) + c3 * exp( a3 * P ); - - density[i][j] = (AA + BB * x + CC * x * x + DD * x * x * x) * 1000.0; - } - } -} - -REGISTER_CATALOG_ENTRY( PVTFunction, - BrineCO2DensityFunction, - string_array const &, string_array const &, real64_array const & ) - -} // namespace PVTProps -} // namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2DensityFunction.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2DensityFunction.hpp deleted file mode 100644 index 911fda1c026..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineCO2DensityFunction.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file BrineCO2DensityFunction.hpp - */ - -#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINECO2DENSITYFUNCTION_HPP_ -#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINECO2DENSITYFUNCTION_HPP_ - -#include "PVTFunctionBase.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -class BrineCO2DensityFunction : public PVTFunction -{ -public: - - BrineCO2DensityFunction( string_array const & inputPara, - string_array const & componentNames, - real64_array const & componentMolarWeight ); - ~BrineCO2DensityFunction() override {} - - - static constexpr auto m_catalogName = "BrineCO2Density"; - static string catalogName() { return m_catalogName; } - virtual string getCatalogName() const override final { return catalogName(); } - - - virtual PVTFuncType functionType() const override - { - return PVTFuncType::DENSITY; - - } - - virtual void evaluation( EvalVarArgs const & pressure, - EvalVarArgs const & temperature, - arraySlice1d< EvalVarArgs const > const & phaseComposition, - EvalVarArgs & value, - bool useMass = 0 ) const override; - - -private: - - void makeTable( string_array const & inputPara ); - - void calculateBrineDensity( real64_array const & pressure, real64_array const & temperature, real64 const & salinity, real64_array2d const & density ); - - TableFunctionPtr m_BrineDensityTable; - localIndex m_CO2Index; - localIndex m_waterIndex; - -}; - -} - -} - -#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINECO2DENSITYFUNCTION_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosityFunction.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosity.cpp similarity index 54% rename from src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosityFunction.cpp rename to src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosity.cpp index 70eb081119a..69367e25dae 100644 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosityFunction.cpp +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosity.cpp @@ -13,39 +13,40 @@ */ /** - * @file BrineViscosityFunction.cpp + * @file BrineViscosity.cpp */ - -#include "constitutive/fluid/PVTFunctions/BrineViscosityFunction.hpp" +#include "constitutive/fluid/PVTFunctions/BrineViscosity.hpp" namespace geosx { using namespace stringutilities; -namespace PVTProps +namespace constitutive { -BrineViscosityFunction::BrineViscosityFunction( string_array const & inputPara, - string_array const & componentNames, - real64_array const & componentMolarWeight ): - PVTFunction( inputPara[1], componentNames, componentMolarWeight ) +namespace PVTProps { - makeCoef( inputPara ); - +BrineViscosity::BrineViscosity( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ): + PVTFunctionBase( inputPara[1], + componentNames, + componentMolarWeight ) +{ + makeCoefficients( inputPara ); } -void BrineViscosityFunction::makeCoef( string_array const & inputPara ) +void BrineViscosity::makeCoefficients( string_array const & inputPara ) { - + // these coefficients come from Phillips et al. (1981), equation (1), pages 5-6 constexpr real64 a = 0.0816; constexpr real64 b = 0.0122; constexpr real64 c = 0.000128; constexpr real64 d = 0.000629; constexpr real64 k = -0.7; - constexpr real64 waterVisc = 8.9e-4; //at 25C real64 m = -1.0; @@ -54,38 +55,29 @@ void BrineViscosityFunction::makeCoef( string_array const & inputPara ) try { - m = stod( inputPara[2] ); - } catch( const std::invalid_argument & e ) { - - GEOSX_ERROR( "Invalid BrineViscosity argument:" + string( e.what())); - + GEOSX_ERROR( "Invalid BrineViscosity argument:" + string( e.what() ) ); } - m_coef0 = (1.0 + a * m + b * m * m + c * m * m * m) * waterVisc; - m_coef1 = d * (1.0 - exp( k * m )) * waterVisc; - } - -void BrineViscosityFunction::evaluation( EvalVarArgs const & GEOSX_UNUSED_PARAM( - pressure ), EvalVarArgs const & temperature, arraySlice1d< EvalVarArgs const > const & GEOSX_UNUSED_PARAM( - phaseComposition ), EvalVarArgs & value, bool GEOSX_UNUSED_PARAM( useMass )) const +BrineViscosity::KernelWrapper BrineViscosity::createKernelWrapper() { - - value = m_coef0 + m_coef1 * temperature; - + return KernelWrapper( m_componentNames, + m_componentMolarWeight, + m_coef0, + m_coef1 ); } -REGISTER_CATALOG_ENTRY( PVTFunction, - BrineViscosityFunction, - string_array const &, string_array const &, real64_array const & ) +REGISTER_CATALOG_ENTRY( PVTFunctionBase, BrineViscosity, string_array const &, string_array const &, array1d< real64 > const & ) -} +} // end namespace PVTProps -} +} // namespace constitutive + +} // end namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosity.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosity.hpp new file mode 100644 index 00000000000..09e56cd6ad2 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosity.hpp @@ -0,0 +1,157 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file BrineViscosity.hpp + */ + +#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINEVISCOSITY_HPP_ +#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINEVISCOSITY_HPP_ + +#include "PVTFunctionBase.hpp" + +namespace geosx +{ + +namespace constitutive +{ + +namespace PVTProps +{ + +class BrineViscosityUpdate final : public PVTFunctionBaseUpdate +{ +public: + + BrineViscosityUpdate( arrayView1d< string const > const & componentNames, + arrayView1d< real64 const > const & componentMolarWeight, + real64 const & coef0, + real64 const & coef1 ) + : PVTFunctionBaseUpdate( componentNames, + componentMolarWeight ), + m_coef0( coef0 ), + m_coef1( coef1 ) + {} + + /// Default copy constructor + BrineViscosityUpdate( BrineViscosityUpdate const & ) = default; + + /// Default move constructor + BrineViscosityUpdate( BrineViscosityUpdate && ) = default; + + /// Deleted copy assignment operator + BrineViscosityUpdate & operator=( BrineViscosityUpdate const & ) = delete; + + /// Deleted move assignment operator + BrineViscosityUpdate & operator=( BrineViscosityUpdate && ) = delete; + + GEOSX_HOST_DEVICE + GEOSX_FORCE_INLINE + virtual void compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass = 0 ) const override; + +protected: + + real64 const m_coef0; + + real64 const m_coef1; + +}; + + +class BrineViscosity : public PVTFunctionBase +{ +public: + + BrineViscosity( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ); + + ~BrineViscosity() override {} + + static string catalogName() { return "BrineViscosity"; } + + virtual string getCatalogName() const override final { return catalogName(); } + + virtual PVTFunctionType functionType() const override + { + return PVTFunctionType::VISCOSITY; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = BrineViscosityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper(); + +private: + + void makeCoefficients( string_array const & inputPara ); + + real64 m_coef0; + + real64 m_coef1; + +}; + +GEOSX_HOST_DEVICE +GEOSX_FORCE_INLINE +void BrineViscosityUpdate::compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass ) const +{ + GEOSX_UNUSED_VAR( pressure ); + GEOSX_UNUSED_VAR( phaseComposition ); + GEOSX_UNUSED_VAR( dPhaseComposition_dPressure ); + GEOSX_UNUSED_VAR( dPhaseComposition_dTemperature ); + GEOSX_UNUSED_VAR( dPhaseComposition_dGlobalCompFraction ); + + GEOSX_UNUSED_VAR( useMass ); + + value = m_coef0 + m_coef1 * temperature; + dValue_dPressure = 0.0; + dValue_dTemperature = m_coef1; + for( real64 & val : dValue_dGlobalCompFraction ) + { + val = 0.0; + } +} + +} // end namespace PVTProps + +} // end namespace constitutive + +} // end namespace geosx + +#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINEVISCOSITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosityFunction.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosityFunction.hpp deleted file mode 100644 index b6878c349ce..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/BrineViscosityFunction.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file BrineViscosityFunction.hpp - */ - -#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINEVISCOSITYFUNCTION_HPP_ -#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINEVISCOSITYFUNCTION_HPP_ - -#include "PVTFunctionBase.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -class BrineViscosityFunction : public PVTFunction -{ -public: - - - BrineViscosityFunction( string_array const & inputPara, - string_array const & componentNames, - real64_array const & componentMolarWeight ); - ~BrineViscosityFunction() override - {} - - static constexpr auto m_catalogName = "BrineViscosity"; - static string catalogName() { return m_catalogName; } - virtual string getCatalogName() const override final { return catalogName(); } - - virtual PVTFuncType functionType() const override - { - return PVTFuncType::VISCOSITY; - - } - - virtual void evaluation( EvalVarArgs const & pressure, - EvalVarArgs const & temperature, - arraySlice1d< EvalVarArgs const > const & phaseComposition, - EvalVarArgs & value, bool useMass = 0 ) const override; - -private: - - void makeCoef( string_array const & inputPara ); - - real64 m_coef0; - real64 m_coef1; - -}; - -} - -} -#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_BRINEVISCOSITYFUNCTION_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/CO2Solubility.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/CO2Solubility.cpp new file mode 100644 index 00000000000..30c3a9e5dba --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/CO2Solubility.cpp @@ -0,0 +1,310 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CO2Solubility.cpp + */ + +#include "constitutive/fluid/PVTFunctions/CO2Solubility.hpp" + +#include "constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp" +#include "managers/Functions/FunctionManager.hpp" +#include "managers/GeosxState.hpp" + +namespace geosx +{ + +using namespace stringutilities; + +namespace constitutive +{ + +namespace PVTProps +{ + +constexpr real64 T_K_f = 273.15; +constexpr real64 P_Pa_f = 1e+5; +constexpr real64 P_c = 73.773 * P_Pa_f; +constexpr real64 T_c = 304.1282; +constexpr real64 Rgas = 8.314467; +constexpr real64 V_c = Rgas*T_c/P_c; + +// these coefficients are in Table (A1) of Duan and Sun (2003) +constexpr real64 acoef[] = +{ 8.99288497e-2, -4.94783127e-1, 4.77922245e-2, 1.03808883e-2, -2.82516861e-2, 9.49887563e-2, 5.20600880e-4, + -2.93540971e-4, -1.77265112e-3, -2.51101973e-5, 8.93353441e-5, 7.88998563e-5, -1.66727022e-2, 1.398, 2.96e-2 }; + +namespace detail +{ + +real64 ff( real64 const & T, real64 const & P, real64 const & V_r ) +{ + // reduced pressure + real64 const P_r = P*P_Pa_f/P_c; + // reduced temperature + real64 const T_r = (T_K_f+T)/T_c; + + // CO2 equation of state + // see equation (A1) in Duan and Sun (2003) + real64 const f_Z = 1.0 + + ( acoef[0] + acoef[1]/(T_r * T_r) + acoef[2]/(T_r * T_r * T_r) )/V_r + + ( acoef[3] + acoef[4]/(T_r * T_r) + acoef[5]/(T_r * T_r * T_r) )/(V_r*V_r) + + ( acoef[6] + acoef[7]/(T_r * T_r) + acoef[8]/(T_r * T_r * T_r) )/(V_r*V_r*V_r*V_r) + + ( acoef[9] + acoef[10]/(T_r * T_r) + acoef[11]/(T_r * T_r * T_r) )/(V_r*V_r*V_r*V_r*V_r) + + acoef[12]/(T_r * T_r * T_r)/(V_r * V_r) * (acoef[13] + acoef[14]/(V_r * V_r)) * exp( -acoef[14]/(V_r * V_r)) - P_r * V_r / T_r; + + return f_Z; +} + +real64 PWater( real64 const & T ) +{ + // these coefficients are defined in Table (B1) of Duan and Sun (2003) + constexpr real64 ccoef[] = { -38.640844, 5.8948420, 59.876516, 26.654627, 10.637097 }; + + // H2O critical pressure (bars) + real64 const P_c_w = 220.85; + // H2O critical temperature (K) + real64 const T_c_w = 647.29; + real64 const tt = ( (T+T_K_f)-T_c_w )/T_c_w; + // Empirical model for water pressure of equation (B1) of Duan and Sun (2003) + real64 const x = (P_c_w*(T+T_K_f)/T_c_w) + * (1 + + ccoef[0]*pow( -tt, 1.9 ) + + ccoef[1]*tt + + ccoef[2]*tt*tt + + ccoef[3]*tt*tt*tt + + ccoef[4]*tt*tt*tt*tt); + + return x; +} + +real64 logF( real64 const & T, real64 const & P, real64 const & V_r ) +{ + // reduced pressure + real64 const P_r = P*P_Pa_f/P_c; + // reduced temperature + real64 const T_r = (T_K_f+T)/T_c; + real64 const Z = P_r * V_r/T_r; + + // fugacity coefficient of CO2, equation (A6) of Duan and Sun (2003) + real64 const log_f = Z - 1 - log( Z ) + + ( acoef[0] + acoef[1]/T_r/T_r + acoef[2]/T_r/T_r/T_r )/V_r + + ( acoef[3] + acoef[4]/T_r/T_r + acoef[5]/T_r/T_r/T_r )/2.0/V_r/V_r + + ( acoef[6] + acoef[7]/T_r/T_r + acoef[8]/T_r/T_r/T_r )/4.0/V_r/V_r/V_r/V_r + + ( acoef[9] + acoef[10]/T_r/T_r + acoef[11]/T_r/T_r/T_r )/5.0/V_r/V_r/V_r/V_r/V_r + + acoef[12]/2.0/T_r/T_r/T_r/acoef[14] * ( acoef[13] + 1.0 - (acoef[13] + 1.0 + acoef[14]/V_r/V_r) * exp( -acoef[14]/V_r/V_r ) ); + + return log_f; +} + +real64 Par( real64 const & T, real64 const & P, real64 const * cc ) +{ + // "equation for the parameters", see equation (7) of Duan and Sun (2003) + real64 x = cc[0] + + cc[1]*T + + cc[2]/T + + cc[3]*T*T + + cc[4]/(630.0-T) + + cc[5]*P + + cc[6]*P *log( T ) + + cc[7]*P/T + + cc[8]*P/(630.0-T) + + cc[9]*P*P/(630.0-T)/(630.0-T) + + cc[10]*T *log( P ); + + return x; +} + +} + +CO2Solubility::CO2Solubility( string_array const & inputPara, + string_array const & phaseNames, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ): + FlashModelBase( inputPara[1], + componentNames, + componentMolarWeight ) +{ + GEOSX_THROW_IF( phaseNames.size() != 2, + "The CO2Solubility model is a two-phase model", + InputError ); + GEOSX_THROW_IF( componentNames.size() != 2, + "The CO2Solubility model is a two-component model", + InputError ); + + char const * expectedCO2ComponentNames[] = { "CO2", "co2" }; + m_CO2Index = PVTFunctionHelpers::findName( componentNames, expectedCO2ComponentNames ); + GEOSX_THROW_IF( m_CO2Index < 0 || m_CO2Index >= componentNames.size(), + "Component CO2 is not found!", + InputError ); + + char const * expectedWaterComponentNames[] = { "Water", "water" }; + m_waterIndex = PVTFunctionHelpers::findName( componentNames, expectedWaterComponentNames ); + GEOSX_THROW_IF( m_waterIndex < 0 || m_waterIndex >= componentNames.size(), + "Component Water/Brine is not found!", + InputError ); + + char const * expectedGasPhaseNames[] = { "CO2", "co2", "gas", "Gas" }; + m_phaseGasIndex = PVTFunctionHelpers::findName( phaseNames, + expectedGasPhaseNames ); + GEOSX_THROW_IF( m_phaseGasIndex < 0 || m_phaseGasIndex >= phaseNames.size(), + "Phase co2/gas is not found!", + InputError ); + + char const * expectedWaterPhaseNames[] = { "Water", "water", "Liquid", "liquid" }; + m_phaseLiquidIndex = PVTFunctionHelpers::findName( phaseNames, + expectedWaterPhaseNames ); + GEOSX_THROW_IF( m_phaseLiquidIndex < 0 || m_phaseLiquidIndex >= phaseNames.size(), + "Phase water/liquid is not found!", + InputError ); + + makeTable( inputPara ); +} + +void CO2Solubility::makeTable( string_array const & inputPara ) +{ + // initialize the (p,T) coordinates + PTTableCoordinates tableCoords; + PVTFunctionHelpers::initializePropertyTable( inputPara, tableCoords ); + + // initialize salinity and tolerance + GEOSX_THROW_IF( inputPara.size() < 9, + "Invalid property input!", + InputError ); + + real64 tolerance = 1e-9; + real64 salinity = 0.0; + try + { + salinity = stod( inputPara[8] ); + if( inputPara.size() >= 10 ) + { + tolerance = stod( inputPara[9] ); + } + } + catch( const std::invalid_argument & e ) + { + GEOSX_THROW( "Invalid property argument:" + string( e.what()), + InputError ); + } + + array1d< real64 > values( tableCoords.nPressures() * tableCoords.nTemperatures() ); + calculateCO2Solubility( tolerance, tableCoords, salinity, values ); + + FunctionManager & functionManager = getGlobalState().getFunctionManager(); + m_CO2SolubilityTable = dynamicCast< TableFunction * >( functionManager.createChild( "TableFunction", "CO2SolubilityTable" ) ); + m_CO2SolubilityTable->setTableCoordinates( tableCoords.getCoords() ); + m_CO2SolubilityTable->setTableValues( values ); + m_CO2SolubilityTable->reInitializeFunction(); + m_CO2SolubilityTable->setInterpolationMethod( TableFunction::InterpolationType::Linear ); +} + +void CO2Solubility::calculateCO2Solubility( real64 const & tolerance, + PTTableCoordinates const & tableCoords, + real64 const & salinity, + array1d< real64 > const & values ) +{ + // Interaction parameters, see Table 2 of Duan and Sun (2003) + constexpr real64 mu[] = + { 28.9447706, -0.0354581768, -4770.67077, 1.02782768e-5, 33.8126098, 9.04037140e-3, + -1.14934031e-3, -0.307405726, -0.0907301486, 9.32713393e-4, 0 }; + constexpr real64 lambda[] = { -0.411370585, 6.07632013e-4, 97.5347708, 0, 0, 0, 0, -0.0237622469, 0.0170656236, 0, 1.41335834e-5 }; + constexpr real64 zeta[] = { 3.36389723e-4, -1.98298980e-5, 0, 0, 0, 0, 0, 2.12220830e-3, -5.24873303e-3, 0, 0 }; + + localIndex const nPressures = tableCoords.nPressures(); + localIndex const nTemperatures = tableCoords.nTemperatures(); + + for( localIndex i = 0; i < nPressures; ++i ) + { + real64 const P = tableCoords.getPressure( i ) / P_Pa_f; + + for( localIndex j = 0; j < nTemperatures; ++j ) + { + real64 const T = tableCoords.getTemperature( j ); + + // compute reduced volume by solving the CO2 equation of state + real64 V_r = 0.0; + CO2SolubilityFunction( tolerance, T, P, V_r, &detail::ff ); + + // compute equation (6) of Duan and Sun (2003) + real64 const logK = detail::Par( T+T_K_f, P, mu ) + - detail::logF( T, P, V_r ) + + 2*detail::Par( T+T_K_f, P, lambda ) * salinity + + detail::Par( T+T_K_f, P, zeta ) * salinity * salinity; + + // mole fraction of CO2 in vapor phase, equation (4) of Duan and Sun (2003) + real64 const y_CO2 = (P - detail::PWater( T ))/P; + values[j*nPressures+i] = y_CO2 * P / exp( logK ); + } + } +} + +void CO2Solubility::CO2SolubilityFunction( real64 const & tolerance, + real64 const & T, + real64 const & P, + real64 & V_r, + real64 (*f)( real64 const & x1, real64 const & x2, real64 const & x3 ) ) +{ + constexpr real64 dx = 1e-10; + int count = 0; + real64 Vr_int = 0.05; + + V_r = 0.75*Rgas*(T_K_f+T)/(P*P_Pa_f)*(1/V_c); + + // iterate until the solution of the CO2 equation of state is found + for(;; ) + { + if( V_r < 0.0 ) + { + V_r = Vr_int; + Vr_int += 0.05; + } + + real64 const v0 = (*f)( T, P, V_r ); + real64 const v1 = (*f)( T, P, V_r+dx ); + real64 const dre = -v0/((v1-v0)/dx); + + if( fabs( dre ) < tolerance ) + { + break; + } + + GEOSX_THROW_IF( count > 50, + "CO2Solubility NR convergence fails! " << "dre = " << dre << ", tolerance = " << tolerance, + InputError ); + + count++; + V_r += dre; + } +} + + +CO2Solubility::KernelWrapper CO2Solubility::createKernelWrapper() +{ + return KernelWrapper( m_componentNames, + m_componentMolarWeight, + m_CO2SolubilityTable, + m_CO2Index, + m_waterIndex, + m_phaseGasIndex, + m_phaseLiquidIndex ); +} + +REGISTER_CATALOG_ENTRY( FlashModelBase, CO2Solubility, string_array const &, string_array const &, string_array const &, array1d< real64 > const & ) + +} // end namespace PVTProps + +} // namespace constitutive + +} // end namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/CO2Solubility.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/CO2Solubility.hpp new file mode 100644 index 00000000000..578bbb6332f --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/CO2Solubility.hpp @@ -0,0 +1,305 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CO2Solubility.hpp + */ + +#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_CO2SOLUBILITY_HPP_ +#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_CO2SOLUBILITY_HPP_ + +#include "FlashModelBase.hpp" + +#include "constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp" +#include "managers/Functions/TableFunction.hpp" + +namespace geosx +{ + +namespace constitutive +{ + +namespace PVTProps +{ + +constexpr real64 minForDivision = 1e-10; + +class CO2SolubilityUpdate final : public FlashModelBaseUpdate +{ +public: + + CO2SolubilityUpdate( arrayView1d< string const > const & componentNames, + arrayView1d< real64 const > const & componentMolarWeight, + TableFunction * CO2SolubilityTable, + localIndex const CO2Index, + localIndex const waterIndex, + localIndex const phaseGasIndex, + localIndex const phaseLiquidIndex ) + : FlashModelBaseUpdate( componentNames, + componentMolarWeight ), + m_CO2SolubilityTable( CO2SolubilityTable->createKernelWrapper() ), + m_CO2Index( CO2Index ), + m_waterIndex( waterIndex ), + m_phaseGasIndex( phaseGasIndex ), + m_phaseLiquidIndex( phaseLiquidIndex ) + {} + + /// Default copy constructor + CO2SolubilityUpdate( CO2SolubilityUpdate const & ) = default; + + /// Default move constructor + CO2SolubilityUpdate( CO2SolubilityUpdate && ) = default; + + /// Deleted copy assignment operator + CO2SolubilityUpdate & operator=( CO2SolubilityUpdate const & ) = delete; + + /// Deleted move assignment operator + CO2SolubilityUpdate & operator=( CO2SolubilityUpdate && ) = delete; + + GEOSX_HOST_DEVICE + GEOSX_FORCE_INLINE + virtual void compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & compFraction, + arraySlice1d< real64 > const & phaseFraction, + arraySlice1d< real64 > const & dPhaseFraction_dPressure, + arraySlice1d< real64 > const & dPhaseFraction_dTemperature, + arraySlice2d< real64 > const & dPhaseFraction_dCompFraction, + arraySlice2d< real64 > const & phaseCompFraction, + arraySlice2d< real64 > const & dPhaseCompFraction_dPressure, + arraySlice2d< real64 > const & dPhaseCompFraction_dTemperature, + arraySlice3d< real64 > const & dPhaseCompFraction_dCompFraction ) const; + +protected: + + /// Table with CO2 solubility tabulated as a function (P,T) + TableFunction::KernelWrapper const m_CO2SolubilityTable; + + /// Index of the CO2 phase + localIndex const m_CO2Index; + + /// Index of the water phase + localIndex const m_waterIndex; + + /// Index of the gas phase + localIndex const m_phaseGasIndex; + + /// Index of the liquid phase + localIndex const m_phaseLiquidIndex; + +}; + +class CO2Solubility : public FlashModelBase +{ +public: + + CO2Solubility( string_array const & inputPara, + string_array const & phaseNames, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ); + + ~CO2Solubility() override {} + + static string catalogName() { return "CO2Solubility"; } + + virtual string getCatalogName() const override final { return catalogName(); } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = CO2SolubilityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper(); + +private: + + void makeTable( string_array const & inputPara ); + + void calculateCO2Solubility( real64 const & tolerance, + PVTProps::PTTableCoordinates const & tableCoords, + real64 const & salinity, + array1d< real64 > const & values ); + + void CO2SolubilityFunction( real64 const & tolerance, + real64 const & T, + real64 const & P, + real64 & V_r, + real64 (*f)( real64 const & x1, real64 const & x2, real64 const & x3 ) ); + + /// Table to compute solubility as a function of pressure and temperature + TableFunction * m_CO2SolubilityTable; + + /// Index of the CO2 component + localIndex m_CO2Index; + + /// Index of the water component + localIndex m_waterIndex; + + /// Index of the gas phase + localIndex m_phaseGasIndex; + + /// Index of the liquid phase + localIndex m_phaseLiquidIndex; +}; + +GEOSX_HOST_DEVICE +GEOSX_FORCE_INLINE +void CO2SolubilityUpdate::compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & compFraction, + arraySlice1d< real64 > const & phaseFraction, + arraySlice1d< real64 > const & dPhaseFraction_dPressure, + arraySlice1d< real64 > const & dPhaseFraction_dTemperature, + arraySlice2d< real64 > const & dPhaseFraction_dCompFraction, + arraySlice2d< real64 > const & phaseCompFraction, + arraySlice2d< real64 > const & dPhaseCompFraction_dPressure, + arraySlice2d< real64 > const & dPhaseCompFraction_dTemperature, + arraySlice3d< real64 > const & dPhaseCompFraction_dCompFraction ) const +{ + // solubility mol/kg(water) X = Csat/W + real64 const input[2] = { pressure, temperature }; + real64 solubility = 0.0; + real64 solubilityDeriv[2]{}; + m_CO2SolubilityTable.compute( input, solubility, solubilityDeriv ); + + solubility *= m_componentMolarWeight[m_waterIndex]; + for( localIndex i = 0; i < 2; ++i ) + { + solubilityDeriv[i] *= m_componentMolarWeight[m_waterIndex]; + } + + real64 Y = 0.0; + real64 dY_dCompFrac[2]{}; + + // Y = C/W = z/(1-z) + + if( compFraction[m_CO2Index] > 1.0 - minForDivision ) + { + Y = compFraction[m_CO2Index] / minForDivision; + dY_dCompFrac[m_CO2Index] = 1.0 / minForDivision; + dY_dCompFrac[m_waterIndex] = 0.0; + } + else + { + real64 const oneMinusCompFracInv = 1.0 / (1.0 - compFraction[m_CO2Index]); + Y = compFraction[m_CO2Index] * oneMinusCompFracInv; + dY_dCompFrac[m_CO2Index] = oneMinusCompFracInv * oneMinusCompFracInv; + dY_dCompFrac[m_waterIndex] = 0.0; + } + + if( Y < solubility ) + { + // liquid phase only + + // 1) Compute phase fractions + + phaseFraction[m_phaseLiquidIndex] = 1.0; + phaseFraction[m_phaseGasIndex] = 0.0; + for( real64 & val : dPhaseFraction_dPressure ) + { + val = 0.0; + } + for( real64 & val : dPhaseFraction_dTemperature ) + { + val = 0.0; + } + for( real64 & val : dPhaseFraction_dCompFraction ) + { + val = 0.0; + } + + // 2) Compute phase component fractions + + for( localIndex ic = 0; ic < 2; ++ic ) + { + phaseCompFraction[m_phaseLiquidIndex][ic] = compFraction[ic]; + // the two following lines are not present in Yue's code, unclear if this will have some consequences + phaseCompFraction[m_phaseGasIndex][m_CO2Index] = 1.0; + phaseCompFraction[m_phaseGasIndex][m_waterIndex] = 0.0; + for( localIndex jc = 0; jc < 2; ++jc ) + { + dPhaseCompFraction_dCompFraction[m_phaseLiquidIndex][ic][jc] = (ic == jc ) ? 1.0 : 0.0; + dPhaseCompFraction_dCompFraction[m_phaseGasIndex][ic][jc] = 0.0; + } + } + for( real64 & val : dPhaseCompFraction_dPressure ) + { + val = 0.0; + } + for( real64 & val : dPhaseCompFraction_dTemperature ) + { + val = 0.0; + } + + } + else + { + // two-phase flow + + // 1) Compute phase fractions + + // liquid phase fraction = (Csat + W) / (C + W) = (Csat/W + 1) / (C/W + 1) + real64 const onePlusYInv = 1.0 / ( 1.0 + Y ); + phaseFraction[m_phaseLiquidIndex] = (solubility + 1.0) * onePlusYInv; + dPhaseFraction_dPressure[m_phaseLiquidIndex] = solubilityDeriv[0] * onePlusYInv; + dPhaseFraction_dTemperature[m_phaseLiquidIndex] = solubilityDeriv[1] * onePlusYInv; + dPhaseFraction_dCompFraction[m_phaseLiquidIndex][m_CO2Index] = + -dY_dCompFrac[m_CO2Index] * phaseFraction[m_phaseLiquidIndex] * onePlusYInv; + dPhaseFraction_dCompFraction[m_phaseLiquidIndex][m_waterIndex] = + -dY_dCompFrac[m_waterIndex] * phaseFraction[m_phaseLiquidIndex] * onePlusYInv; + + phaseFraction[m_phaseGasIndex] = 1.0 - phaseFraction[m_phaseLiquidIndex]; + dPhaseFraction_dPressure[m_phaseGasIndex] = -dPhaseFraction_dPressure[m_phaseLiquidIndex]; + dPhaseFraction_dTemperature[m_phaseGasIndex] = -dPhaseFraction_dTemperature[m_phaseLiquidIndex]; + dPhaseFraction_dCompFraction[m_phaseGasIndex][m_CO2Index] = -dPhaseFraction_dCompFraction[m_phaseLiquidIndex][m_CO2Index]; + dPhaseFraction_dCompFraction[m_phaseGasIndex][m_waterIndex] = -dPhaseFraction_dCompFraction[m_phaseLiquidIndex][m_waterIndex]; + + // 2) Compute phase component fractions + + // liquid phase composition CO2 = Csat / (Csat + W) = (Csat/W) / (Csat/W + 1) + real64 const onePlusSolubilityInv = 1.0 / ( 1.0 + solubility ); + phaseCompFraction[m_phaseLiquidIndex][m_CO2Index] = solubility * onePlusSolubilityInv; + dPhaseCompFraction_dPressure[m_phaseLiquidIndex][m_CO2Index] = solubilityDeriv[0] * (onePlusSolubilityInv*onePlusSolubilityInv); + dPhaseCompFraction_dTemperature[m_phaseLiquidIndex][m_CO2Index] = solubilityDeriv[1] * (onePlusSolubilityInv*onePlusSolubilityInv); + + phaseCompFraction[m_phaseLiquidIndex][m_waterIndex] = 1.0 - phaseCompFraction[m_phaseLiquidIndex][m_CO2Index]; + dPhaseCompFraction_dPressure[m_phaseLiquidIndex][m_waterIndex] = -dPhaseCompFraction_dPressure[m_phaseLiquidIndex][m_CO2Index]; + dPhaseCompFraction_dTemperature[m_phaseLiquidIndex][m_waterIndex] = -dPhaseCompFraction_dTemperature[m_phaseLiquidIndex][m_CO2Index]; + + // gas phase composition CO2 = 1.0 + + phaseCompFraction[m_phaseGasIndex][m_CO2Index] = 1.0; + phaseCompFraction[m_phaseGasIndex][m_waterIndex] = 0.0; + dPhaseCompFraction_dPressure[m_phaseGasIndex][m_CO2Index] = 0.0; + dPhaseCompFraction_dPressure[m_phaseGasIndex][m_waterIndex] = 0.0; + dPhaseCompFraction_dTemperature[m_phaseGasIndex][m_CO2Index] = 0.0; + dPhaseCompFraction_dTemperature[m_phaseGasIndex][m_waterIndex] = 0.0; + + // phaseCompFraction does not depend on globalComponentFraction + for( real64 & val : dPhaseCompFraction_dCompFraction ) + { + val = 0.0; + } + } +} + +} // end namespace PVTProps + +} // end namespace constitutive + +} // end namespace geosx + +#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_CO2SOLUBILITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/CO2SolubilityFunction.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/CO2SolubilityFunction.cpp deleted file mode 100644 index 9cee477216e..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/CO2SolubilityFunction.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file CO2SolubilityFunction.cpp - */ - - -#include "constitutive/fluid/PVTFunctions/CO2SolubilityFunction.hpp" - -namespace geosx -{ - -using namespace stringutilities; - - -namespace PVTProps -{ - -constexpr real64 minForDivision = 1e-10; - -constexpr real64 T_K_f = 273.15; -constexpr real64 P_Pa_f = 1e+5; -constexpr real64 P_c = 73.773 * P_Pa_f; -constexpr real64 T_c = 304.1282; -constexpr real64 Rgas = 8.314467; -constexpr real64 V_c = Rgas*T_c/P_c; - -constexpr real64 acoef[] = -{8.99288497e-2, -4.94783127e-1, 4.77922245e-2, 1.03808883e-2, -2.82516861e-2, 9.49887563e-2, 5.20600880e-4, -2.93540971e-4, -1.77265112e-3, -2.51101973e-5, - 8.93353441e-5, 7.88998563e-5, -1.66727022e-2, 1.398, 2.96e-2}; - - -real64 ff( real64 const & T, real64 const & P, real64 const & V_r ) -{ - real64 const P_r = P*P_Pa_f/P_c; - real64 const T_r = (T_K_f+T)/T_c; - - real64 const f_Z = 1.0 + (acoef[0] + acoef[1]/(T_r * T_r) + acoef[2]/(T_r*T_r*T_r))/V_r + (acoef[3] + acoef[4]/(T_r*T_r) + acoef[5]/(T_r*T_r*T_r))/(V_r*V_r) + - (acoef[6] + acoef[7]/(T_r*T_r) + acoef[8]/(T_r*T_r*T_r))/(V_r*V_r*V_r*V_r) + (acoef[9] + acoef[10]/(T_r*T_r) + acoef[11]/(T_r*T_r*T_r))/ - (V_r*V_r*V_r*V_r*V_r) + acoef[12]/(T_r*T_r*T_r)/(V_r*V_r) * (acoef[13] + acoef[14]/(V_r*V_r)) * exp( -acoef[14]/(V_r*V_r)) - P_r * V_r / - T_r; - - return f_Z; -} - -real64 PWater( real64 const & T ) -{ - constexpr real64 ccoef[] = {-38.640844, 5.8948420, 59.876516, 26.654627, 10.637097}; - - real64 const P_c_w = 220.85; // H2O critical pressure (bars) - real64 const T_c_w = 647.29; // H2O critical temperature (K) - real64 const tt = ((T+T_K_f)-T_c_w)/T_c_w; - real64 const x = (P_c_w*(T+T_K_f)/T_c_w) * (1 + ccoef[0]*pow( -tt, 1.9 ) + ccoef[1]*tt + ccoef[2]*tt*tt + ccoef[3]*tt*tt*tt + ccoef[4]*tt*tt*tt*tt); - - return x; -} - -real64 logF( real64 const & T, real64 const & P, real64 const & V_r ) -{ - real64 const P_r = P*P_Pa_f/P_c; - real64 const T_r = (T_K_f+T)/T_c; - - real64 const Z=P_r * V_r/T_r; - - real64 const log_f = Z - 1 - log( Z ) + (acoef[0] + acoef[1]/T_r/T_r + acoef[2]/T_r/T_r/T_r)/V_r + (acoef[3] + acoef[4]/T_r/T_r + acoef[5]/T_r/T_r/T_r)/2.0/ - V_r/V_r + (acoef[6] + acoef[7]/T_r/T_r + acoef[8]/T_r/T_r/T_r)/4.0/V_r/V_r/V_r/V_r + - (acoef[9] + acoef[10]/T_r/T_r + acoef[11]/T_r/T_r/T_r)/5.0/V_r/V_r/ - V_r/V_r/V_r + acoef[12]/2.0/T_r/T_r/T_r/acoef[14] * - (acoef[13] + 1.0 - (acoef[13] + 1.0 + acoef[14]/V_r/V_r) * exp( -acoef[14]/V_r/V_r )); - - return log_f; -} - -real64 Par( real64 const & T, real64 const & P, real64 const * cc ) -{ - real64 x = cc[0] + cc[1]*T +cc[2]/T + cc[3]*T*T + cc[4]/(630.0-T) + cc[5]*P + cc[6] *P *log( T ) + cc[7]*P/T + cc[8]*P/(630.0-T) + cc[9]*P*P/(630.0-T)/ - (630.0-T) + cc[10] *T *log( P ); - - return x; -} - -void CO2Solubility( real64 const & T, real64 const & P, real64 & V_r, real64 (*f)( real64 const & x1, real64 const & x2, real64 const & x3 )) -{ - - constexpr real64 eps = 1e-9; - int count = 0; - constexpr real64 dx = 1e-10; - - real64 dre; - real64 Vr_int = 0.05; - - V_r = 0.75*Rgas*(T_K_f+T)/(P*P_Pa_f)*(1/V_c); - - real64 v1, v0; - - for(;; ) - { - - if( V_r < 0.0 ) - { - V_r = Vr_int; - Vr_int += 0.05; - } - - v0 = (*f)( T, P, V_r ); - v1 = (*f)( T, P, V_r+dx ); - dre = -v0/((v1-v0)/dx); - - if( fabs( dre ) < eps ) - break; - - GEOSX_ERROR_IF( count > 50, "CO2Solubiltiy NR convergence fails! " << "dre = " << dre << ", eps = " << eps ); - - count++; - - V_r += dre; - } -} - -void CalculateCO2Solubility( real64_array const & pressure, real64_array const & temperature, real64 const & salinity, real64_array2d const & solubiltiy ) -{ - - real64 T, P, V_r, m, logK, y_CO2; - - constexpr real64 mu[] = - {28.9447706, -0.0354581768, -4770.67077, 1.02782768e-5, 33.8126098, 9.04037140e-3, -1.14934031e-3, -0.307405726, -0.0907301486, 9.32713393e-4, 0}; - - constexpr real64 lambda[] = {-0.411370585, 6.07632013e-4, 97.5347708, 0, 0, 0, 0, -0.0237622469, 0.0170656236, 0, 1.41335834e-5}; - - constexpr real64 zeta[] = {3.36389723e-4, -1.98298980e-5, 0, 0, 0, 0, 0, 2.12220830e-3, -5.24873303e-3, 0, 0}; - - m = salinity; - - for( localIndex i = 0; i < pressure.size(); ++i ) - { - - P = pressure[i] / P_Pa_f; - - for( localIndex j = 0; j < temperature.size(); ++j ) - { - - T = temperature[j]; - - CO2Solubility( T, P, V_r, &ff ); - - logK = Par( T+T_K_f, P, mu ) - logF( T, P, V_r ) + 2*Par( T+T_K_f, P, lambda )*m + Par( T+T_K_f, P, zeta )*m*m; - - y_CO2 = (P - PWater( T ))/P; - - solubiltiy[i][j] = y_CO2 * P / exp( logK ); - - } - - } - -} - - -CO2SolubilityFunction::CO2SolubilityFunction( string_array const & inputPara, - string_array const & phaseNames, - string_array const & componentNames, - real64_array const & componentMolarWeight ): - FlashModel( inputPara[1], componentNames, componentMolarWeight ) -{ - - bool notFound = 1; - - for( localIndex i = 0; i < componentNames.size(); ++i ) - { - - if( componentNames[i] == "CO2" || componentNames[i] == "co2" ) - { - m_CO2Index = i; - notFound = 0; - break; - } - - } - - GEOSX_ERROR_IF( notFound, "Component CO2 is not found!" ); - - notFound = 1; - - for( localIndex i = 0; i < componentNames.size(); ++i ) - { - - if( componentNames[i] == "Water" || componentNames[i] == "water" ) - { - m_waterIndex = i; - notFound = 0; - break; - } - - } - - GEOSX_ERROR_IF( notFound, "Component Water/Brine is not found!" ); - - - notFound = 1; - - for( localIndex i = 0; i < phaseNames.size(); ++i ) - { - - if( phaseNames[i] == "CO2" || phaseNames[i] == "co2" || phaseNames[i] == "gas" || phaseNames[i] == "Gas" ) - { - m_phaseGasIndex = i; - notFound = 0; - break; - } - - } - - GEOSX_ERROR_IF( notFound, "Phase co2/gas is not found!" ); - - notFound = 1; - - for( localIndex i = 0; i < phaseNames.size(); ++i ) - { - - if( phaseNames[i] == "Water" || phaseNames[i] == "water" || phaseNames[i] == "Liquid" || phaseNames[i] == "liquid" ) - { - m_phaseLiquidIndex = i; - notFound = 0; - break; - } - - } - - GEOSX_ERROR_IF( notFound, "Phase water/liquid is not found!" ); - - makeTable( inputPara ); - -} - -void CO2SolubilityFunction::makeTable( string_array const & inputPara ) -{ - - real64_array pressures; - real64_array temperatures; - - real64 PStart, PEnd, dP; - real64 TStart, TEnd, dT; - real64 P, T, m; - - dT = -1.0; - dP = -1.0; - TStart = -1.0; - TEnd = -1.0; - PStart = -1.0; - PEnd = -1.0; - - GEOSX_ERROR_IF( inputPara.size() < 9, "Invalid CO2Solubility input!" ); - - try - { - - PStart = stod( inputPara[2] ); - PEnd = stod( inputPara[3] ); - dP = stod( inputPara[4] ); - - TStart = stod( inputPara[5] ); - TEnd = stod( inputPara[6] ); - dT = stod( inputPara[7] ); - - m = stod( inputPara[8] ); - - } - catch( const std::invalid_argument & e ) - { - - GEOSX_ERROR( "Invalid CO2Solubility argument:" + string( e.what())); - - } - - P = PStart; - - while( P <= PEnd ) - { - - pressures.emplace_back( P ); - P += dP; - - } - - T = TStart; - - while( T <= TEnd ) - { - - temperatures.emplace_back( T ); - T += dT; - - } - - localIndex const nP = pressures.size(); - localIndex const nT = temperatures.size(); - - real64_array2d solubilities( nP, nT ); - - CalculateCO2Solubility( pressures, temperatures, m, solubilities ); - - m_CO2SolubilityTable = std::make_shared< XYTable >( "CO2SolubilityTable", pressures, temperatures, solubilities ); - - -} - -void CO2SolubilityFunction::partition( EvalVarArgs const & pressure, EvalVarArgs const & temperature, arraySlice1d< EvalVarArgs const > const & compFraction, - arraySlice1d< EvalVarArgs > const & phaseFraction, arraySlice2d< EvalVarArgs > const & phaseCompFraction ) const -{ - - EvalArgs2D P, T, solubility; - P.m_var = pressure.m_var; - P.m_der[0] = 1.0; - - T.m_var = temperature.m_var; - T.m_der[1] = 1.0; - - //solubiltiy mol/kg(water) X = Csat/W - solubility = m_CO2SolubilityTable->value( P, T ); - - real64 const waterMW = m_componentMolarWeight[m_waterIndex]; - - solubility *= waterMW; - - EvalVarArgs X, Y; - - X.m_var = solubility.m_var; - X.m_der[0] = solubility.m_der[0]; - - //Y = C/W = z/(1-z) - - if( compFraction[m_CO2Index].m_var > 1.0 - minForDivision ) - { - Y = compFraction[m_CO2Index] / minForDivision; - } - else - { - Y = compFraction[m_CO2Index] / (1.0 - compFraction[m_CO2Index]); - } - - if( Y < X ) - { - //liquid phase only - - phaseFraction[m_phaseLiquidIndex] = 1.0; - phaseFraction[m_phaseGasIndex] = 0.0; - - for( localIndex c = 0; c < m_componentNames.size(); ++c ) - { - phaseCompFraction[m_phaseLiquidIndex][c] = compFraction[c]; - } - - } - else - { - // two-phase - // liquid phase fraction = (Csat + W) / (C + W) = (Csat/W + 1) / (C/W + 1) - - phaseFraction[m_phaseLiquidIndex] = (X + 1.0)/ (Y + 1.0); - phaseFraction[m_phaseGasIndex] = 1.0 - phaseFraction[m_phaseLiquidIndex]; - - //liquid phase composition CO2 = Csat / (Csat + W) = (Csat/W) / (Csat/W + 1) - - phaseCompFraction[m_phaseLiquidIndex][m_CO2Index] = X / (X + 1.0); - phaseCompFraction[m_phaseLiquidIndex][m_waterIndex] = 1.0 - phaseCompFraction[m_phaseLiquidIndex][m_CO2Index]; - - //gas phase composition CO2 = 1.0 - - phaseCompFraction[m_phaseGasIndex][m_CO2Index] = 1.0; - phaseCompFraction[m_phaseGasIndex][m_waterIndex] = 0.0; - - } -} - - -REGISTER_CATALOG_ENTRY( FlashModel, - CO2SolubilityFunction, - string_array const &, string_array const &, string_array const &, real64_array const & ) - -} - -} diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/CO2SolubilityFunction.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/CO2SolubilityFunction.hpp deleted file mode 100644 index 175e7d89424..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/CO2SolubilityFunction.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file CO2SolubilityFunction.hpp - */ - -#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_CO2SOLUBILITYFUNCTION_HPP_ -#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_CO2SOLUBILITYFUNCTION_HPP_ - -#include "FlashModelBase.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -class CO2SolubilityFunction : public FlashModel -{ -public: - - CO2SolubilityFunction( string_array const & inputPara, - string_array const & phaseNames, - string_array const & componentNames, - real64_array const & componentMolarWeight ); - - ~CO2SolubilityFunction() override - {} - - static constexpr auto m_catalogName = "CO2Solubility"; - static string catalogName() { return m_catalogName; } - virtual string getCatalogName() const override final { return catalogName(); } - - virtual void partition( EvalVarArgs const & pressure, - EvalVarArgs const & temperature, - arraySlice1d< EvalVarArgs const > const & compFraction, - arraySlice1d< EvalVarArgs > const & phaseFraction, - arraySlice2d< EvalVarArgs > const & phaseCompFraction ) const override; - -private: - - void makeTable( const string_array & inputPara ); - - TableFunctionPtr m_CO2SolubilityTable; - localIndex m_CO2Index; - localIndex m_waterIndex; - localIndex m_phaseGasIndex; - localIndex m_phaseLiquidIndex; -}; - -} - -} - -#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_CO2SOLUBILITYFUNCTION_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.cpp new file mode 100644 index 00000000000..289ba4f9902 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.cpp @@ -0,0 +1,146 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FenghourCO2Viscosity.cpp + */ + +#include "constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.hpp" + +#include "constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.hpp" +#include "managers/Functions/FunctionManager.hpp" +#include "managers/GeosxState.hpp" + +namespace geosx +{ + +namespace constitutive +{ + +namespace PVTProps +{ + +FenghourCO2Viscosity::FenghourCO2Viscosity( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ): + PVTFunctionBase( inputPara[1], + componentNames, + componentMolarWeight ) +{ + makeTable( inputPara ); +} + +void FenghourCO2Viscosity::makeTable( string_array const & inputPara ) +{ + PTTableCoordinates tableCoords; + PVTFunctionHelpers::initializePropertyTable( inputPara, tableCoords ); + + real64 tolerance = 1e-10; + try + { + if( inputPara.size() >= 9 ) + { + tolerance = stod( inputPara[8] ); + } + } + catch( const std::invalid_argument & e ) + { + GEOSX_THROW( "Invalid property argument:" + string( e.what()), + InputError ); + } + + localIndex const nP = tableCoords.nPressures(); + localIndex const nT = tableCoords.nTemperatures(); + array1d< real64 > density( nP * nT ); + array1d< real64 > viscosity( nP * nT ); + SpanWagnerCO2Density::calculateCO2Density( tolerance, tableCoords, density ); + calculateCO2Viscosity( tableCoords, density, viscosity ); + + FunctionManager & functionManager = getGlobalState().getFunctionManager(); + m_CO2ViscosityTable = dynamicCast< TableFunction * >( functionManager.createChild( "TableFunction", "CO2ViscosityTable" ) ); + m_CO2ViscosityTable->setTableCoordinates( tableCoords.getCoords() ); + m_CO2ViscosityTable->setTableValues( viscosity ); + m_CO2ViscosityTable->reInitializeFunction(); + m_CO2ViscosityTable->setInterpolationMethod( TableFunction::InterpolationType::Linear ); +} + +void FenghourCO2Viscosity::fenghourCO2ViscosityFunction( real64 const & temperatureCent, + real64 const & density, + real64 & viscosity ) +{ + constexpr real64 espar = 251.196; + constexpr real64 esparInv = 1.0 / espar; + // coefficients from Table (1) of Fenghour and Wakeham (1998) + constexpr real64 aa[5] = { 0.235156, -0.491266, 5.211155e-2, 5.347906e-2, -1.537102e-2 }; + // coefficients from Table (3) of Fenghour and Wakeham (1998) + constexpr real64 d11 = 0.4071119e-2; + constexpr real64 d21 = 0.7198037e-4; + constexpr real64 d64 = 0.2411697e-16; + constexpr real64 d81 = 0.2971072e-22; + constexpr real64 d82 = -0.1627888e-22; + // we neglect critical viscosity + constexpr real64 vcrit = 0.0; + + // temperature in Kelvin + real64 const temperatureKelvin = temperatureCent + 273.15; + // equation (5) of Fenghour and Wakeham (1998) + real64 const Tred = temperatureKelvin * esparInv; + real64 const x = log( Tred ); + // equation (4) of Fenghour and Wakeham (1998) + real64 const lnGfun = aa[0] + x * (aa[1] + x * (aa[2] + x *(aa[3] + x * aa[4]))); + real64 const GfunInv = exp( -lnGfun ); + // equation (3) of Fenghour and Wakeham (1998) + real64 const vlimit = 1.00697 * sqrt( temperatureKelvin ) * GfunInv; + + // equation (8) of Fenghour and Wakeham (1998) + real64 const d2 = density * density; + real64 const vxcess = density * (d11 + density * (d21 + d2*d2*(d64 / (Tred*Tred*Tred) + d2*(d81 + d82/Tred)))); + + // equation (1) of Fenghour and Wakeham (1998) + viscosity = 1e-6 * (vlimit + vxcess + vcrit); +} + +void FenghourCO2Viscosity::calculateCO2Viscosity( PTTableCoordinates const & tableCoords, + array1d< real64 > const & densities, + array1d< real64 > const & viscosities ) +{ + + localIndex const nPressures = tableCoords.nPressures(); + localIndex const nTemperatures = tableCoords.nTemperatures(); + + for( localIndex i = 0; i < nPressures; ++i ) + { + for( localIndex j = 0; j < nTemperatures; ++j ) + { + fenghourCO2ViscosityFunction( tableCoords.getTemperature( j ), + densities[j*nPressures+i], + viscosities[j*nPressures+i] ); + } + } +} + +FenghourCO2Viscosity::KernelWrapper FenghourCO2Viscosity::createKernelWrapper() +{ + return KernelWrapper( m_componentNames, + m_componentMolarWeight, + m_CO2ViscosityTable ); +} + +REGISTER_CATALOG_ENTRY( PVTFunctionBase, FenghourCO2Viscosity, string_array const &, string_array const &, array1d< real64 > const & ) + +} // end namespace PVTProps + +} // namespace constitutive + +} // end namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.hpp new file mode 100644 index 00000000000..0307d1fdc30 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.hpp @@ -0,0 +1,163 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FenghourCO2Viscosity.hpp + */ + +#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FENGHOURCO2VISCOSITY_HPP_ +#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FENGHOURCO2VISCOSITY_HPP_ + +#include "PVTFunctionBase.hpp" + +#include "constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp" +#include "managers/Functions/TableFunction.hpp" + +namespace geosx +{ + +namespace constitutive +{ + +namespace PVTProps +{ + +class FenghourCO2ViscosityUpdate final : public PVTFunctionBaseUpdate +{ +public: + + FenghourCO2ViscosityUpdate( arrayView1d< string const > const & componentNames, + arrayView1d< real64 const > const & componentMolarWeight, + TableFunction * CO2ViscosityTable ) + : PVTFunctionBaseUpdate( componentNames, + componentMolarWeight ), + m_CO2ViscosityTable( CO2ViscosityTable->createKernelWrapper() ) + {} + + /// Default copy constructor + FenghourCO2ViscosityUpdate( FenghourCO2ViscosityUpdate const & ) = default; + + /// Default move constructor + FenghourCO2ViscosityUpdate( FenghourCO2ViscosityUpdate && ) = default; + + /// Deleted copy assignment operator + FenghourCO2ViscosityUpdate & operator=( FenghourCO2ViscosityUpdate const & ) = delete; + + /// Deleted move assignment operator + FenghourCO2ViscosityUpdate & operator=( FenghourCO2ViscosityUpdate && ) = delete; + + GEOSX_HOST_DEVICE + GEOSX_FORCE_INLINE + virtual void compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass = 0 ) const override; + +protected: + + /// Table with viscosity tabulated as a function (P,T) + TableFunction::KernelWrapper const m_CO2ViscosityTable; + +}; + +class FenghourCO2Viscosity : public PVTFunctionBase +{ +public: + + FenghourCO2Viscosity( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ); + ~FenghourCO2Viscosity() override {} + + static string catalogName() { return "FenghourCO2Viscosity"; } + + virtual string getCatalogName() const override final { return catalogName(); } + + virtual PVTFunctionType functionType() const override + { + return PVTFunctionType::VISCOSITY; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = FenghourCO2ViscosityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper(); + +private: + + void makeTable( string_array const & inputPara ); + + void calculateCO2Viscosity( PVTProps::PTTableCoordinates const & tableCoords, + array1d< real64 > const & density, + array1d< real64 > const & viscosity ); + + void fenghourCO2ViscosityFunction( real64 const & temperatureCent, + real64 const & density, + real64 & viscosity ); + + /// Table with CO2 viscosity tabulated as a function of (P,T) + TableFunction * m_CO2ViscosityTable; + +}; + +GEOSX_HOST_DEVICE +GEOSX_FORCE_INLINE +void FenghourCO2ViscosityUpdate::compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass ) const +{ + GEOSX_UNUSED_VAR( phaseComposition ); + GEOSX_UNUSED_VAR( dPhaseComposition_dPressure ); + GEOSX_UNUSED_VAR( dPhaseComposition_dTemperature ); + GEOSX_UNUSED_VAR( dPhaseComposition_dGlobalCompFraction ); + GEOSX_UNUSED_VAR( useMass ); + + real64 const input[2] = { pressure, temperature }; + real64 densityDeriv[2]{}; + m_CO2ViscosityTable.compute( input, value, densityDeriv ); + dValue_dPressure = densityDeriv[0]; + dValue_dTemperature = densityDeriv[1]; + + for( real64 & val : dValue_dGlobalCompFraction ) + { + val = 0.0; + } +} + +} // end namespace PVTProps + +} // end namespace constitutive + +} // end namespace geosx + +#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FENGHOURCO2VISCOSITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2ViscosityFunction.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2ViscosityFunction.cpp deleted file mode 100644 index 4ce0b2cb8d5..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2ViscosityFunction.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file FenghourCO2ViscosityFunction.cpp - */ - - -#include "constitutive/fluid/PVTFunctions/FenghourCO2ViscosityFunction.hpp" -#include "constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -FenghourCO2ViscosityFunction::FenghourCO2ViscosityFunction( string_array const & inputPara, - string_array const & componentNames, - real64_array const & componentMolarWeight ): - PVTFunction( inputPara[1], componentNames, componentMolarWeight ) -{ - - makeTable( inputPara ); - -} - -void FenghourCO2ViscosityFunction::makeTable( string_array const & inputPara ) -{ - - real64_array pressures; - real64_array temperatures; - - real64 PStart, PEnd, dP; - real64 TStart, TEnd, dT; - real64 P, T; - - dT = -1.0; - dP = -1.0; - TStart = -1.0; - TEnd = -1.0; - PStart = -1.0; - PEnd = -1.0; - - GEOSX_ERROR_IF( inputPara.size() < 8, "Invalid FenghourCO2Viscosity input!" ); - - try - { - - PStart = stod( inputPara[2] ); - PEnd = stod( inputPara[3] ); - dP = stod( inputPara[4] ); - - TStart = stod( inputPara[5] ); - TEnd = stod( inputPara[6] ); - dT = stod( inputPara[7] ); - - } - catch( const std::invalid_argument & e ) - { - - GEOSX_ERROR( "Invalid FenghourCO2Viscosity argument:" + string( e.what())); - - } - - P = PStart; - - while( P <= PEnd ) - { - pressures.emplace_back( P ); - P += dP; - } - - T = TStart; - - while( T <= TEnd ) - { - temperatures.emplace_back( T ); - T += dT; - } - - localIndex nP = pressures.size(); - localIndex nT = temperatures.size(); - - real64_array2d viscosities( nP, nT ); - real64_array2d densities( nP, nT ); - - SpanWagnerCO2DensityFunction::calculateCO2Density( pressures, temperatures, densities ); - - calculateCO2Viscosity( pressures, temperatures, densities, viscosities ); - - m_CO2ViscosityTable = std::make_shared< XYTable >( "FenghourCO2ViscosityTable", pressures, temperatures, viscosities ); - -} - -void FenghourCO2ViscosityFunction::evaluation( EvalVarArgs const & pressure, EvalVarArgs const & temperature, arraySlice1d< EvalVarArgs const > const & GEOSX_UNUSED_PARAM( - phaseComposition ), EvalVarArgs & value, bool GEOSX_UNUSED_PARAM( useMass )) const -{ - EvalArgs2D P, T, viscosity; - P.m_var = pressure.m_var; - P.m_der[0] = 1.0; - - T.m_var = temperature.m_var; - T.m_der[1] = 1.0; - - viscosity = m_CO2ViscosityTable->value( P, T ); - - value.m_var = viscosity.m_var; - value.m_der[0] = viscosity.m_der[0]; -} - -void FenghourCO2ViscosityFunction::fenghourCO2Viscosity( real64 const & Tcent, real64 const & den, real64 & vis ) -{ - constexpr real64 espar = 251.196; - constexpr real64 esparInv = 1.0 / espar; - constexpr real64 aa[5] = { 0.235156, -0.491266, 5.211155e-2, 5.347906e-2, -1.537102e-2 }; - constexpr real64 d11 = 0.4071119e-2; - constexpr real64 d21 = 0.7198037e-4; - constexpr real64 d64 = 0.2411697e-16; - constexpr real64 d81 = 0.2971072e-22; - constexpr real64 d82 = -0.1627888e-22; - - // temperature in Kelvin - const real64 Tkelvin = Tcent + 273.15; - // evaluate vlimit from eqns 3-5 - const real64 Tred = Tkelvin * esparInv; - const real64 x = log( Tred ); - const real64 lnGfun = aa[0] + x * (aa[1] + x * (aa[2] + x *(aa[3] + x * aa[4]))); - const real64 GfunInv = exp( -lnGfun ); - const real64 vlimit = 1.00697 * sqrt( Tkelvin ) * GfunInv; - - const real64 d2 = den * den; - const real64 vxcess = den * (d11 + den * (d21 + d2*d2*(d64 / (Tred*Tred*Tred) + d2*(d81 + d82/Tred)))); - - constexpr real64 vcrit = 0.0; - - vis = 1e-6 * (vlimit + vxcess + vcrit); -} - -void FenghourCO2ViscosityFunction::calculateCO2Viscosity( real64_array const & pressure, real64_array const & temperature, real64_array2d const & density, - real64_array2d const & viscosity ) -{ - for( localIndex i = 0; i < pressure.size(); ++i ) - { - for( localIndex j = 0; j < temperature.size(); ++j ) - { - fenghourCO2Viscosity( temperature[j], density[i][j], viscosity[i][j] ); - } - } -} - - -REGISTER_CATALOG_ENTRY( PVTFunction, - FenghourCO2ViscosityFunction, - string_array const &, string_array const &, real64_array const & ) - -} - -} diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2ViscosityFunction.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2ViscosityFunction.hpp deleted file mode 100644 index 20e173d16f9..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/FenghourCO2ViscosityFunction.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file FenghourCO2ViscosityFunction.hpp - */ - -#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FENGHOURCO2VISCOSITYFUNCTION_HPP_ -#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FENGHOURCO2VISCOSITYFUNCTION_HPP_ - -#include "PVTFunctionBase.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -class FenghourCO2ViscosityFunction : public PVTFunction -{ -public: - - FenghourCO2ViscosityFunction( string_array const & inputPara, - string_array const & componentNames, - real64_array const & componentMolarWeight ); - ~FenghourCO2ViscosityFunction() override - {} - - static constexpr auto m_catalogName = "FenghourCO2Viscosity"; - static string catalogName() { return m_catalogName; } - virtual string getCatalogName() const override final { return catalogName(); } - - virtual PVTFuncType functionType() const override - { - return PVTFuncType::VISCOSITY; - - } - - virtual void evaluation( EvalVarArgs const & pressure, - EvalVarArgs const & temperature, - arraySlice1d< EvalVarArgs const > const & phaseComposition, - EvalVarArgs & value, bool useMass = 0 ) const override; - - -private: - - void makeTable( string_array const & inputPara ); - - void calculateCO2Viscosity( real64_array const & pressure, real64_array const & temperature, real64_array2d const & density, - real64_array2d const & viscosity ); - - void fenghourCO2Viscosity( real64 const & Tcent, real64 const & den, real64 & vis ); - - TableFunctionPtr m_CO2ViscosityTable; -}; - -} - -} -#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FENGHOURCO2VISCOSITYFUNCTION_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/FlashModelBase.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/FlashModelBase.hpp index f65f4e2264e..9be4ae19518 100644 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/FlashModelBase.hpp +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/FlashModelBase.hpp @@ -19,66 +19,113 @@ #ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FLASHMODELBASE_HPP_ #define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FLASHMODELBASE_HPP_ -#include "constitutive/fluid/PVTFunctions/UtilityFunctions.hpp" #include "codingUtilities/StringUtilities.hpp" +#include "dataRepository/ObjectCatalog.hpp" namespace geosx { +namespace constitutive +{ + namespace PVTProps { +class FlashModelBaseUpdate +{ +public: + + FlashModelBaseUpdate( arrayView1d< string const > const & componentNames, + arrayView1d< real64 const > const & componentMolarWeight ) + : + m_componentNames( componentNames ), + m_componentMolarWeight( componentMolarWeight ) + {} + + /// Default virtual destructor + virtual ~FlashModelBaseUpdate() = default; + + /// Default copy constructor + FlashModelBaseUpdate( FlashModelBaseUpdate const & ) = default; + + /// Default move constructor + FlashModelBaseUpdate( FlashModelBaseUpdate && ) = default; + + /// Deleted copy assignment operator + FlashModelBaseUpdate & operator=( FlashModelBaseUpdate const & ) = delete; + + /// Deleted move assignment operator + FlashModelBaseUpdate & operator=( FlashModelBaseUpdate && ) = delete; + + GEOSX_HOST_DEVICE + virtual void compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & compFraction, + arraySlice1d< real64 > const & phaseFraction, + arraySlice1d< real64 > const & dPhaseFraction_dPressure, + arraySlice1d< real64 > const & dPhaseFraction_dTemperature, + arraySlice2d< real64 > const & dPhaseFraction_dCompFraction, + arraySlice2d< real64 > const & phaseCompFraction, + arraySlice2d< real64 > const & dPhaseCompFraction_dPressure, + arraySlice2d< real64 > const & dPhaseCompFraction_dTemperature, + arraySlice3d< real64 > const & dPhaseCompFraction_dCompFraction ) const = 0; + +protected: -class FlashModel + /// Array storing the name of the components + arrayView1d< string const > m_componentNames; + + /// Array storing the component molar weights + arrayView1d< real64 const > m_componentMolarWeight; + +}; + + +class FlashModelBase { public: - FlashModel( string const & name, - string_array const & componentNames, - real64_array const & componentMolarWeight ): + FlashModelBase( string const & name, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ): m_modelName( name ), m_componentNames( componentNames ), m_componentMolarWeight( componentMolarWeight ) {} - virtual ~FlashModel(){} + virtual ~FlashModelBase() = default; - using CatalogInterface = dataRepository::CatalogInterface< FlashModel, string_array const &, + using CatalogInterface = dataRepository::CatalogInterface< FlashModelBase, string_array const &, string_array const &, string_array const &, - real64_array const & >; + array1d< real64 > const & >; static typename CatalogInterface::CatalogType & getCatalog() { static CatalogInterface::CatalogType catalog; return catalog; } - virtual string getCatalogName() const = 0; + virtual string getCatalogName() const = 0; - string const & flashModelName() const - { - return m_modelName; - } - - //partition - //input: P, T, totalCompFraction - //output: phaseFraction, phaseCompFraction - - virtual void partition( EvalVarArgs const & pressure, - EvalVarArgs const & temperature, - arraySlice1d< EvalVarArgs const > const & compFraction, - arraySlice1d< EvalVarArgs > const & phaseFraction, - arraySlice2d< EvalVarArgs > const & phaseCompFraction ) const = 0; + string const & flashModelName() const { return m_modelName; } protected: + + /// Name the solubility model string m_modelName; + + /// Array storing the name of the components string_array m_componentNames; - real64_array m_componentMolarWeight; + + /// Array storing the component molar weights + array1d< real64 > m_componentMolarWeight; }; -} +} // end namespace PVTProps + +} // end namespace constitutive -} +} // end namespace geosx #endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_FLASHMODELBASE_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/PVTFunctionBase.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/PVTFunctionBase.hpp index f1c2aed8731..98063907cee 100644 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/PVTFunctionBase.hpp +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/PVTFunctionBase.hpp @@ -19,66 +19,116 @@ #ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_PVTFUNCTIONBASE_HPP_ #define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_PVTFUNCTIONBASE_HPP_ -#include "constitutive/fluid/PVTFunctions/UtilityFunctions.hpp" #include "codingUtilities/StringUtilities.hpp" +#include "dataRepository/ObjectCatalog.hpp" namespace geosx { +namespace constitutive +{ + namespace PVTProps { -enum class PVTFuncType {UNKNOWN, DENSITY, VISCOSITY}; +enum class PVTFunctionType { UNKNOWN, DENSITY, VISCOSITY }; + +class PVTFunctionBaseUpdate +{ +public: + PVTFunctionBaseUpdate( arrayView1d< string const > const & componentNames, + arrayView1d< real64 const > const & componentMolarWeight ) + : + m_componentNames( componentNames ), + m_componentMolarWeight( componentMolarWeight ) + {} + + /// Default virtual destructor + virtual ~PVTFunctionBaseUpdate() = default; + + /// Default copy constructor + PVTFunctionBaseUpdate( PVTFunctionBaseUpdate const & ) = default; + + /// Default move constructor + PVTFunctionBaseUpdate( PVTFunctionBaseUpdate && ) = default; + + /// Deleted copy assignment operator + PVTFunctionBaseUpdate & operator=( PVTFunctionBaseUpdate const & ) = delete; + + /// Deleted move assignment operator + PVTFunctionBaseUpdate & operator=( PVTFunctionBaseUpdate && ) = delete; + + GEOSX_HOST_DEVICE + virtual void compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass = 0 ) const = 0; + +protected: + + /// Array storing the name of the components + arrayView1d< string const > m_componentNames; + + /// Array storing the component molar weights + arrayView1d< real64 const > m_componentMolarWeight; + +}; -class PVTFunction +class PVTFunctionBase { + public: - PVTFunction( string const & name, string_array const & componentNames, real64_array const & componentMolarWeight ): + PVTFunctionBase( string const & name, + array1d< string > const & componentNames, + array1d< real64 > const & componentMolarWeight ) + : m_functionName( name ), m_componentNames( componentNames ), m_componentMolarWeight( componentMolarWeight ) {} - virtual ~PVTFunction(){} + virtual ~PVTFunctionBase() = default; - - using CatalogInterface = dataRepository::CatalogInterface< PVTFunction, string_array const &, - string_array const &, - real64_array const & >; + using CatalogInterface = dataRepository::CatalogInterface< PVTFunctionBase, array1d< string > const &, + array1d< string > const &, + array1d< real64 > const & >; static typename CatalogInterface::CatalogType & getCatalog() { static CatalogInterface::CatalogType catalog; return catalog; } - virtual string getCatalogName() const = 0; + virtual string getCatalogName() const = 0; - string const & functionName() const - { - return m_functionName; - } - - virtual PVTFuncType functionType() const = 0; - - //phase density/viscosity - //input: P, T, phaseCompFraction - //output: phase density/viscoty + string const & functionName() const { return m_functionName; } - virtual void evaluation( EvalVarArgs const & pressure, EvalVarArgs const & temperature, arraySlice1d< EvalVarArgs const > const & phaseComposition, - EvalVarArgs & value, bool useMass = 0 ) const = 0; + virtual PVTFunctionType functionType() const = 0; protected: + /// Name of the PVT function string m_functionName; - string_array m_componentNames; - real64_array m_componentMolarWeight; + /// Array storing the name of the components + array1d< string > m_componentNames; + + /// Array storing the component molar weights + array1d< real64 > m_componentMolarWeight; }; -} +} // end namespace PVTProps + +} // end namespace constitutive -} +} // end namespace geosx #endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_PVTFUNCTIONBASE_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp new file mode 100644 index 00000000000..687979aa471 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp @@ -0,0 +1,131 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PVTFunctionHelpers.hpp + */ + +#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_PVTFUNCTIONHELPERS_HPP +#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_PVTFUNCTIONHELPERS_HPP + +namespace geosx +{ + +namespace constitutive +{ + +namespace PVTProps +{ + +class PTTableCoordinates +{ +public: + PTTableCoordinates() + { coords.resize( 2 ); } + + localIndex nPressures() const { return coords[coordType::PRES].size(); } + localIndex nTemperatures() const { return coords[coordType::TEMP].size(); } + + void appendPressure( const real64 & pres ) { coords[coordType::PRES].emplace_back( pres ); } + void appendTemperature( const real64 & temp ) { coords[coordType::TEMP].emplace_back( temp ); } + + real64 const & getPressure( localIndex i ) const { return coords[coordType::PRES][i]; } + real64 const & getTemperature( localIndex i ) const { return coords[coordType::TEMP][i]; } + + array1d< array1d< real64 > > const & getCoords() const { return coords; } + +private: + + struct coordType + { + static constexpr integer PRES = 0; + static constexpr integer TEMP = 1; + }; + + array1d< array1d< real64 > > coords; +}; + +struct PVTFunctionHelpers +{ + + /** + * @brief Look for the expectedNames in the names provided by the user + * @tparam InputRange type of the input range + * @tparam ExpectedRange type of the expected range + * @param[in] inputNames phase or component names provided by the user + * @param[in] expectedNames expected names that can be accepted by GEOSX + * @return the index of the phase or component that was found + */ + template< typename InputRange, typename ExpectedRange > + static localIndex + findName( InputRange const & inputNames, + ExpectedRange const & expectedNames ) + { + using std::begin; + using std::end; + auto it = std::find_first_of( begin( inputNames ), end( inputNames ), begin( expectedNames ), end( expectedNames ) ); + localIndex const id = std::distance( begin( inputNames ), it ); + return id; + } + + /** + * @brief Populate the coordinate table with pressure and temperature + * @param[in] inputParameters the strings reads in the file provided by the user + * @param[inout] tableCoords the (p,T) coordinates of the table + */ + static void + initializePropertyTable( string_array const & inputParameters, + PTTableCoordinates & tableCoords ) + + { + GEOSX_THROW_IF( inputParameters.size() < 8, + "Invalid property input!", + InputError ); + + try + { + real64 const PStart = stod( inputParameters[2] ); + real64 const PEnd = stod( inputParameters[3] ); + real64 const dP = stod( inputParameters[4] ); + + real64 const TStart = stod( inputParameters[5] ); + real64 const TEnd = stod( inputParameters[6] ); + real64 const dT = stod( inputParameters[7] ); + + for( real64 P = PStart; P <= PEnd; P += dP ) + { + tableCoords.appendPressure( P ); + } + for( real64 T = TStart; T <= TEnd; T += dT ) + { + tableCoords.appendTemperature( T ); + } + } + catch( const std::invalid_argument & e ) + { + GEOSX_THROW( "Invalid property argument:" + string( e.what()), + InputError ); + } + } + +}; + +} // namespace PVTProps + +} // namespace constitutive + +} // namespace geosx + + +#endif diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.cpp similarity index 56% rename from src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.cpp rename to src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.cpp index 056d6b48fa8..881024e0eb3 100644 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.cpp +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.cpp @@ -13,23 +13,34 @@ */ /** - * @file SpanWagnerCO2DensityFunction.cpp + * @file SpanWagnerCO2Density.cpp */ +#include "constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.hpp" -#include "constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.hpp" +#include "managers/Functions/FunctionManager.hpp" +#include "managers/GeosxState.hpp" namespace geosx { using namespace stringutilities; +namespace constitutive +{ + namespace PVTProps { -//calc density based on table 3 -real64 f( const real64 & T, const real64 & P, const real64 & rho ) +namespace detail +{ + +real64 f( real64 const & T, + real64 const & P, + real64 const & rho ) { + // all the coefficients below are defined in Table (31) of Span and Wagner (1996) + // the variable names used below follow the notation of the Table constexpr real64 n[] = {0.38856823203161, 2.938547594274, -5.5867188534934, -0.76753199592477, 0.31729005580416, 0.54803315897767, 0.12279411220335, 2.165896154322, 1.5841735109724, -0.23132705405503, 0.058116916431436, -0.55369137205382, 0.48946615909422, -0.024275739843501, 0.062494790501678, -0.12175860225246, @@ -74,11 +85,13 @@ real64 f( const real64 & T, const real64 & P, const real64 & rho ) constexpr real64 R = 188.9241; - real64 tau = T_c / T; - real64 delta = rho / rho_c; + real64 const tau = T_c / T; + real64 const delta = rho / rho_c; real64 theta, Delta, Phi, dPhi_delta, dDelta_delta, dDelta_delta_b; + // residual part of the energy equation + // this is defined in Table (32) of Span and Wagner (1996) real64 phi_r_delta = 0.0; for( int i=0; i<7; i++ ) @@ -120,217 +133,117 @@ real64 f( const real64 & T, const real64 & P, const real64 & rho ) phi_r_delta += n[i] * (pow( Delta, b[i] ) * (Phi + delta *dPhi_delta) + dDelta_delta_b * delta * Phi); } + // Helmholtz energy equation: see equation (2.2) from Span and Wagner (1996) return rho * (1.0 + delta * phi_r_delta) / (P / (R * T)) - 1.0; } +} -SpanWagnerCO2DensityFunction::SpanWagnerCO2DensityFunction( string_array const & inputPara, string_array const & componentNames, - real64_array const & componentMolarWeight ): PVTFunction( inputPara[1], componentNames, - componentMolarWeight ) +SpanWagnerCO2Density::SpanWagnerCO2Density( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ): + PVTFunctionBase( inputPara[1], + componentNames, + componentMolarWeight ) { - - bool notFound = 1; - - for( localIndex i = 0; i < componentNames.size(); ++i ) - { - - if( componentNames[i] == "CO2" || componentNames[i] == "co2" ) - { - m_CO2Index = i; - notFound = 0; - break; - } - - } - - GEOSX_ERROR_IF( notFound, "Component CO2 is not found!" ); + char const * expectedCO2ComponentNames[] = { "CO2", "co2" }; + m_CO2Index = PVTFunctionHelpers::findName( componentNames, expectedCO2ComponentNames ); + GEOSX_THROW_IF( m_CO2Index < 0 || m_CO2Index >= componentNames.size(), + "Component CO2 is not found!", + InputError ); makeTable( inputPara ); - } -void SpanWagnerCO2DensityFunction::makeTable( string_array const & inputPara ) +void SpanWagnerCO2Density::makeTable( string_array const & inputPara ) { + PTTableCoordinates tableCoords; + PVTFunctionHelpers::initializePropertyTable( inputPara, tableCoords ); - real64_array pressures; - real64_array temperatures; - - real64 PStart, PEnd, dP; - real64 TStart, TEnd, dT; - real64 P, T; - - dT = -1.0; - dP = -1.0; - TStart = -1.0; - TEnd = -1.0; - PStart = -1.0; - PEnd = -1.0; - - GEOSX_ERROR_IF( inputPara.size() < 8, "Invalid SpanWagnerCO2Density input!" ); - + real64 tolerance = 1e-10; try { - - PStart = stod( inputPara[2] ); - PEnd = stod( inputPara[3] ); - dP = stod( inputPara[4] ); - - TStart = stod( inputPara[5] ); - TEnd = stod( inputPara[6] ); - dT = stod( inputPara[7] ); - + if( inputPara.size() >= 9 ) + { + tolerance = stod( inputPara[8] ); + } } catch( const std::invalid_argument & e ) { - - GEOSX_ERROR( "Invalid SpanWagnerCO2Density argument:" + string( e.what())); - - } - - P = PStart; - - while( P <= PEnd ) - { - - pressures.emplace_back( P ); - P += dP; - + GEOSX_THROW( "Invalid property argument:" + string( e.what()), + InputError ); } - T = TStart; - - while( T <= TEnd ) - { - - temperatures.emplace_back( T ); - T += dT; - - } - - localIndex nP = pressures.size(); - localIndex nT = temperatures.size(); - - real64_array2d densities( nP, nT ); - - calculateCO2Density( pressures, temperatures, densities ); - - m_CO2DensityTable = std::make_shared< XYTable >( "SpanWagnerCO2DensityTable", pressures, temperatures, densities ); - + array1d< real64 > densities( tableCoords.nPressures() * tableCoords.nTemperatures() ); + calculateCO2Density( tolerance, tableCoords, densities ); + FunctionManager & functionManager = getGlobalState().getFunctionManager(); + m_CO2DensityTable = dynamicCast< TableFunction * >( functionManager.createChild( "TableFunction", "CO2DensityTable" ) ); + m_CO2DensityTable->setTableCoordinates( tableCoords.getCoords() ); + m_CO2DensityTable->setTableValues( densities ); + m_CO2DensityTable->reInitializeFunction(); + m_CO2DensityTable->setInterpolationMethod( TableFunction::InterpolationType::Linear ); } -void SpanWagnerCO2DensityFunction::evaluation( EvalVarArgs const & pressure, EvalVarArgs const & temperature, arraySlice1d< EvalVarArgs const > const & GEOSX_UNUSED_PARAM( - phaseComposition ), EvalVarArgs & value, bool useMass ) const +void SpanWagnerCO2Density::calculateCO2Density( real64 const & tolerance, + PTTableCoordinates const & tableCoords, + array1d< real64 > const & densities ) { - EvalArgs2D P, T, density; - P.m_var = pressure.m_var; - P.m_der[0] = 1.0; + constexpr real64 TK_f = 273.15; - T.m_var = temperature.m_var; - T.m_der[1] = 1.0; + localIndex const nPressures = tableCoords.nPressures(); + localIndex const nTemperatures = tableCoords.nTemperatures(); - density = m_CO2DensityTable->value( P, T ); - - real64 CO2MW = m_componentMolarWeight[m_CO2Index]; - - if( !useMass ) - { - - density /= CO2MW; - - } - - value.m_var = density.m_var; - value.m_der[0] = density.m_der[0]; - -} - -void SpanWagnerCO2DensityFunction::calculateCO2Density( real64_array const & pressure, real64_array const & temperature, real64_array2d const & density ) -{ - - constexpr real64 T_K_f = 273.15; - - real64 PPa, TK; - - for( localIndex i = 0; i < pressure.size(); ++i ) + for( localIndex i = 0; i < nPressures; ++i ) { - - PPa = pressure[i]; - - for( localIndex j = 0; j < temperature.size(); ++j ) + real64 const PPa = tableCoords.getPressure( i ); + for( localIndex j = 0; j < nTemperatures; ++j ) { - - TK = temperature[j] + T_K_f; - - spanWagnerCO2Density( TK, PPa, density[i][j], &f ); - + real64 const TK = tableCoords.getTemperature( j ) + TK_f; + spanWagnerCO2DensityFunction( tolerance, TK, PPa, densities[j*nPressures+i], &detail::f ); } - } } -void SpanWagnerCO2DensityFunction::spanWagnerCO2Density( real64 const & T, real64 const & P, real64 & rho, real64 (*f)( real64 const & x1, real64 const & x2, - real64 const & x3 )) +void SpanWagnerCO2Density::spanWagnerCO2DensityFunction( real64 const & tolerance, + real64 const & T, + real64 const & P, + real64 & rho, + real64 (*f)( real64 const & x1, real64 const & x2, real64 const & x3 ) ) { constexpr real64 P_Pa_f = 1e+5; - constexpr real64 P_c = 73.773 * P_Pa_f; constexpr real64 T_c = 304.1282; constexpr real64 rho_c = 467.6; - constexpr real64 R = 188.9241; - // constexpr real64 Rgas = 8.314467; + constexpr real64 vpa[] = { -7.0602087, 1.9391218, -1.6463597, -3.2995634 }; + constexpr real64 vpt[] = { 1.0, 1.5, 2.0, 4.0 }; - // constexpr real64 V_c = Rgas*T_c/P_c; + constexpr real64 lda[] = { 1.9245108, -0.62385555, -0.32731127, 0.39245142 }; + constexpr real64 ldt[] = { 0.340, 0.5, 1.6666666667, 1.833333333 }; - - constexpr real64 vpa[] = {-7.0602087, 1.9391218, -1.6463597, -3.2995634}; - constexpr real64 vpt[] = {1.0, 1.5, 2.0, 4.0}; - - constexpr real64 lda[] = {1.9245108, -0.62385555, -0.32731127, 0.39245142}; - constexpr real64 ldt[] = {0.340, 0.5, 1.6666666667, 1.833333333}; - - // constexpr real64 vda[] = {-1.7074879, -0.82274670, -4.6008549, -10.111178, -29.742252}; - // constexpr real64 vdt[] = {0.340, 0.5, 1.0, 2.3333333333, 4.6666666667}; - - - real64 eps = 1e-10; + real64 const dx = 1e-10; int count = 0; - real64 dx = 1e-10; - - real64 dre, sum; - real64 psat, denl; - - //initial guess + // initial guess if( T < T_c ) { - sum = 0; - for( int i=0; i<4; i++ ) + real64 sum = 0; + for( int i=0; i < 4; i++ ) { sum += vpa[i] * pow( 1.0 - T / T_c, vpt[i] ); } - - psat = P_c * exp( T_c / T * sum ); + real64 const psat = P_c * exp( T_c / T * sum ); sum = 0; - for( int i=0; i<4; i++ ) + for( int i=0; i < 4; i++ ) { sum += lda[i] * pow( 1.0 - T / T_c, ldt[i] ); } - - denl = rho_c * exp( sum ); - - /* - sum = 0; - for(int i=0; i<5; i++) - sum += vda[i] * pow(1.0 - T / T_c, vdt[i]); - - denv = rho_c * exp(sum); - */ + real64 const denl = rho_c * exp( sum ); if( P >= psat ) { @@ -346,31 +259,36 @@ void SpanWagnerCO2DensityFunction::spanWagnerCO2Density( real64 const & T, real6 rho = 1.0 / (30.0 + R * T / P); } - real64 v1, v0; - + // Newton loop for(;; ) { - v0 = (*f)( T, P, rho ); - v1 = (*f)( T, P, rho+dx ); - dre = -v0/((v1-v0)/dx); - - if( fabs( dre ) < eps ) + real64 const v0 = (*f)( T, P, rho ); + real64 const v1 = (*f)( T, P, rho+dx ); + real64 const dre = -v0/((v1-v0)/dx); + if( fabs( dre ) < tolerance ) + { break; + } - GEOSX_ERROR_IF( count > 50, "SpanWagnerCO2Density NR convergence fails! " << "dre = " << dre << ", eps = " << eps ); + GEOSX_ERROR_IF( count > 50, "SpanWagnerCO2Density NR convergence fails! " << "dre = " << dre << ", tolerance = " << tolerance ); count++; - rho += dre; } } +SpanWagnerCO2Density::KernelWrapper SpanWagnerCO2Density::createKernelWrapper() +{ + return KernelWrapper( m_componentNames, + m_componentMolarWeight, + m_CO2DensityTable, + m_CO2Index ); +} +REGISTER_CATALOG_ENTRY( PVTFunctionBase, SpanWagnerCO2Density, string_array const &, string_array const &, array1d< real64 > const & ) -REGISTER_CATALOG_ENTRY( PVTFunction, - SpanWagnerCO2DensityFunction, - string_array const &, string_array const &, real64_array const & ) +} // namespace PVTProps -} +} // namespace constitutive -} +} // namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.hpp new file mode 100644 index 00000000000..e9248e4f0f9 --- /dev/null +++ b/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.hpp @@ -0,0 +1,182 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SpanWagnerCO2Density.hpp + */ + +#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_SPANWAGNERCO2DENSITY_HPP_ +#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_SPANWAGNERCO2DENSITY_HPP_ + +#include "PVTFunctionBase.hpp" + +#include "constitutive/fluid/PVTFunctions/PVTFunctionHelpers.hpp" +#include "managers/Functions/TableFunction.hpp" + +namespace geosx +{ + +namespace constitutive +{ + +namespace PVTProps +{ + +class SpanWagnerCO2DensityUpdate final : public PVTFunctionBaseUpdate +{ +public: + + SpanWagnerCO2DensityUpdate( arrayView1d< string const > const & componentNames, + arrayView1d< real64 const > const & componentMolarWeight, + TableFunction * CO2DensityTable, + localIndex const CO2Index ) + : PVTFunctionBaseUpdate( componentNames, + componentMolarWeight ), + m_CO2DensityTable( CO2DensityTable->createKernelWrapper() ), + m_CO2Index( CO2Index ) + {} + + /// Default copy constructor + SpanWagnerCO2DensityUpdate( SpanWagnerCO2DensityUpdate const & ) = default; + + /// Default move constructor + SpanWagnerCO2DensityUpdate( SpanWagnerCO2DensityUpdate && ) = default; + + /// Deleted copy assignment operator + SpanWagnerCO2DensityUpdate & operator=( SpanWagnerCO2DensityUpdate const & ) = delete; + + /// Deleted move assignment operator + SpanWagnerCO2DensityUpdate & operator=( SpanWagnerCO2DensityUpdate && ) = delete; + + GEOSX_HOST_DEVICE + GEOSX_FORCE_INLINE + virtual void compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass = 0 ) const override; + +protected: + + /// Table with brine density tabulated as a function (P,T,sal) + TableFunction::KernelWrapper const m_CO2DensityTable; + + /// Index of the CO2 component + localIndex const m_CO2Index; + +}; + +class SpanWagnerCO2Density : public PVTFunctionBase +{ +public: + + SpanWagnerCO2Density( string_array const & inputPara, + string_array const & componentNames, + array1d< real64 > const & componentMolarWeight ); + + ~SpanWagnerCO2Density() override {} + + static string catalogName() { return "SpanWagnerCO2Density"; } + + virtual string getCatalogName() const override final { return catalogName(); } + + virtual PVTFunctionType functionType() const override + { + return PVTFunctionType::DENSITY; + } + + /// Type of kernel wrapper for in-kernel update + using KernelWrapper = SpanWagnerCO2DensityUpdate; + + /** + * @brief Create an update kernel wrapper. + * @return the wrapper + */ + KernelWrapper createKernelWrapper(); + + static + void calculateCO2Density( real64 const & tolerance, + PVTProps::PTTableCoordinates const & tableCoords, + array1d< real64 > const & densities ); + +private: + + void makeTable( string_array const & inputPara ); + + static + void spanWagnerCO2DensityFunction( real64 const & tolerance, + real64 const & T, + real64 const & P, + real64 & rho, + real64 (*f)( real64 const & x1, real64 const & x2, real64 const & x3 ) ); + + /// Table with CO2 density tabulated as a function of (P,T) + TableFunction * m_CO2DensityTable; + + /// Index of the CO2 component + localIndex m_CO2Index; + +}; + +GEOSX_HOST_DEVICE +GEOSX_FORCE_INLINE +void SpanWagnerCO2DensityUpdate::compute( real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 const > const & phaseComposition, + arraySlice1d< real64 const > const & dPhaseComposition_dPressure, + arraySlice1d< real64 const > const & dPhaseComposition_dTemperature, + arraySlice2d< real64 const > const & dPhaseComposition_dGlobalCompFraction, + real64 & value, + real64 & dValue_dPressure, + real64 & dValue_dTemperature, + arraySlice1d< real64 > const & dValue_dGlobalCompFraction, + bool useMass ) const +{ + GEOSX_UNUSED_VAR( phaseComposition ); + GEOSX_UNUSED_VAR( dPhaseComposition_dPressure ); + GEOSX_UNUSED_VAR( dPhaseComposition_dTemperature ); + GEOSX_UNUSED_VAR( dPhaseComposition_dGlobalCompFraction ); + + real64 const input[2] = { pressure, temperature }; + real64 densityDeriv[2]{}; + m_CO2DensityTable.compute( input, value, densityDeriv ); + dValue_dPressure = densityDeriv[0]; + dValue_dTemperature = densityDeriv[1]; + + if( !useMass ) + { + value /= m_componentMolarWeight[m_CO2Index]; + dValue_dPressure /= m_componentMolarWeight[m_CO2Index]; + dValue_dTemperature /= m_componentMolarWeight[m_CO2Index]; + } + + for( real64 & val : dValue_dGlobalCompFraction ) + { + val = 0.0; + } +} + +} // end namespace PVTProps + +} // end namespace constitutive + +} // end namespace geosx + +#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_SPANWAGNERCO2DENSITY_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.hpp deleted file mode 100644 index 5b7700653b6..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/SpanWagnerCO2DensityFunction.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SpanWagnerCO2DensityFunction.hpp - */ - -#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_SPANWAGNERCO2DENSITYFUNCTION_HPP_ -#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_SPANWAGNERCO2DENSITYFUNCTION_HPP_ - -#include "PVTFunctionBase.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -class SpanWagnerCO2DensityFunction : public PVTFunction -{ -public: - - - SpanWagnerCO2DensityFunction( string_array const & inputPara, - string_array const & componentNames, - real64_array const & componentMolarWeight ); - - ~SpanWagnerCO2DensityFunction() override {} - - - static constexpr auto m_catalogName = "SpanWagnerCO2Density"; - static string catalogName() { return m_catalogName; } - virtual string getCatalogName() const override final { return catalogName(); } - - - virtual PVTFuncType functionType() const override - { - return PVTFuncType::DENSITY; - } - - virtual void evaluation( EvalVarArgs const & pressure, EvalVarArgs const & temperature, arraySlice1d< EvalVarArgs const > const & phaseComposition, - EvalVarArgs & value, bool useMass = 0 ) const override; - - static void calculateCO2Density( real64_array const & pressure, real64_array const & temperature, real64_array2d const & density ); - -private: - - void makeTable( string_array const & inputPara ); - - static void spanWagnerCO2Density( real64 const & T, real64 const & P, real64 & rho, real64 (*f)( real64 const & x1, real64 const & x2, real64 const & x3 )); - - - TableFunctionPtr m_CO2DensityTable; - localIndex m_CO2Index; - -}; - -} - -} - -#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_SPANWAGNERCO2DENSITYFUNCTION_HPP_ diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/UtilityFunctions.cpp b/src/coreComponents/constitutive/fluid/PVTFunctions/UtilityFunctions.cpp deleted file mode 100644 index 2f3146004a6..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/UtilityFunctions.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file UtilityFunctions.cpp - */ - - -#include "constitutive/fluid/PVTFunctions/UtilityFunctions.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -EvalArgs2D XYTable::value( EvalArgs2D const & x, EvalArgs2D const & y ) const -{ - localIndex_array xIndices( 2 ), yIndices( 2 ); - - //find i index - - if( x <= m_x[0] ) - { - xIndices[0] = 0; - } - else if( x >= m_x[m_x.size()-2] ) - { - xIndices[0] = m_x.size()-2; - } - else - { - for( localIndex i = 1; i < m_x.size(); ++i ) - { - if( x <= m_x[i] ) - { - xIndices[0] = i - 1; - break; - } - } - } - - xIndices[1] = xIndices[0] + 1; - - EvalArgs2D xWeight = (x - m_x[xIndices[0] ]) / (m_x[xIndices[1] ] - m_x[xIndices[0] ]); - - //find j index - - if( y <= m_y[0] ) - { - yIndices[0] = 0; - } - else if( y >= m_y[m_y.size()-2] ) - { - yIndices[0] = m_y.size()-2; - } - else - { - for( localIndex i = 1; i < m_y.size(); ++i ) - { - - if( y <= m_y[i] ) - { - yIndices[0] = i - 1; - break; - } - } - } - - yIndices[1] = yIndices[0] + 1; - - EvalArgs2D yWeight = (y - m_y[yIndices[0] ]) / (m_y[yIndices[1] ] - m_y[yIndices[0] ]); - - EvalArgs2D out = m_value[xIndices[0] ][yIndices[0] ] * (1.0 - xWeight) * (1.0 - yWeight) + m_value[xIndices[0] ][yIndices[1] ] * (1.0 - xWeight) * yWeight + - m_value[xIndices[1] ][yIndices[1] ] * xWeight * yWeight + m_value[xIndices[1] ][yIndices[0] ] * xWeight * (1.0 - yWeight); - - return out; -} - - -template< class T > -T XTable::getValue( T const & x ) const -{ - - localIndex idx = 0; - //find i index - - if( x <= m_x[0] ) - { - idx = 0; - } - else if( x >= m_x[m_x.size()-1] ) - { - idx = m_x.size()-2; - } - else - { - for( localIndex i = 1; i < m_x.size(); ++i ) - { - if( x <= m_x[i] ) - { - idx = i - 1; - break; - } - } - } - - T weight = (x - m_x[idx]) / (m_x[idx + 1] - m_x[idx]); - - T out = m_value[idx] * (1.0 - weight) + m_value[idx + 1] * weight; - - return out; -} - - -} // namespace PVTProps -} // namespace geosx diff --git a/src/coreComponents/constitutive/fluid/PVTFunctions/UtilityFunctions.hpp b/src/coreComponents/constitutive/fluid/PVTFunctions/UtilityFunctions.hpp deleted file mode 100644 index be0b247df0b..00000000000 --- a/src/coreComponents/constitutive/fluid/PVTFunctions/UtilityFunctions.hpp +++ /dev/null @@ -1,549 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2018-2020 Total, S.A - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file TableFunction.hpp - */ - -#ifndef GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_UTILITYFUNCTION_HPP_ -#define GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_UTILITYFUNCTION_HPP_ - -#include "common/DataTypes.hpp" -#include "constitutive/fluid/MultiFluidBase.hpp" - -namespace geosx -{ - -namespace PVTProps -{ - -constexpr localIndex MAX_VAR_DIM = 10; - -template< typename T, int Dim > -class EvalArgs -{ -public: - - EvalArgs() - { - m_var = 0.0; - for( int i = 0; i < Dim; ++i ) - { - m_der[i] = 0; - } - } - - ~EvalArgs() = default; - - EvalArgs( const EvalArgs & arg ) - { - m_var = arg.m_var; - for( int i = 0; i < Dim; ++i ) - { - m_der[i] = arg.m_der[i]; - } - } - - EvalArgs( const T & var ) - { - m_var = var; - for( int i = 0; i < Dim; ++i ) - { - m_der[i] = 0; - } - } - - EvalArgs & operator+=( const EvalArgs & arg ) - { - this->m_var += arg.m_var; - for( localIndex i = 0; i < Dim; ++i ) - { - this->m_der[i] += arg.m_der[i]; - } - - return *this; - } - - - EvalArgs & operator-=( const EvalArgs & arg ) - { - this->m_var -= arg.m_var; - for( localIndex i = 0; i < Dim; ++i ) - { - this->m_der[i] -= arg.m_der[i]; - } - - return *this; - } - - EvalArgs & operator*=( const EvalArgs & arg ) - { - const T & u = this->m_var; - const T & v = arg.m_var; - for( localIndex i = 0; i < Dim; ++i ) - { - const T & uDer = this->m_der[i]; - const T & vDer = arg.m_der[i]; - - this->m_der[i] = (v * uDer + u * vDer); - } - - this->m_var *= v; - return *this; - } - - - EvalArgs & operator/=( const EvalArgs & arg ) - { - const T & u = this->m_var; - const T & v = arg.m_var; - for( localIndex i = 0; i < Dim; ++i ) - { - const T & uDer = this->m_der[i]; - const T & vDer = arg.m_der[i]; - - this->m_der[i] = (v * uDer - u * vDer) /(v * v); - } - - this->m_var /= v; - return *this; - } - - EvalArgs & exponent( const EvalArgs & arg ) - { - const T & v = arg.m_var; - this->m_var = exp( v ); - for( localIndex i = 0; i < Dim; ++i ) - { - const T & vDer = arg.m_der[i]; - this->m_der[i] = this->m_var * vDer; - } - - return *this; - } - - EvalArgs operator+( const EvalArgs & arg ) const - { - EvalArgs result( *this ); - result += arg; - return result; - } - - EvalArgs operator-( const EvalArgs & arg ) const - { - EvalArgs result( *this ); - result -= arg; - return result; - } - - EvalArgs operator-() const - { - EvalArgs result; - result.m_var = -this->m_var; - for( localIndex i = 0; i < Dim; ++i ) - { - result.m_der[i] = -this->m_der[i]; - } - - return result; - } - - EvalArgs operator*( const EvalArgs & arg ) const - { - EvalArgs result( *this ); - result *= arg; - return result; - } - - EvalArgs operator/( const EvalArgs & arg ) const - { - EvalArgs result( *this ); - result /= arg; - return result; - } - - EvalArgs & operator=( const EvalArgs & arg ) - { - this->m_var = arg.m_var; - for( int i = 0; i < Dim; ++i ) - { - m_der[i] = arg.m_der[i]; - } - - return *this; - } - - bool operator==( const EvalArgs & arg ) const - { - if( this->m_var != arg._m_var ) return false; - - for( localIndex i = 0; i < Dim; ++i ) - { - if( this->m_der[i] != arg.m_der[i] ) return false; - } - - return true; - } - - bool operator!=( const EvalArgs & arg ) const - { - return !(*this == arg); - } - - bool operator>( const EvalArgs & arg ) const - { - return this->m_var > arg.m_var; - } - - bool operator<( const EvalArgs & arg ) const - { - return this->m_var < arg.m_var; - } - - bool operator>=( const EvalArgs & arg ) const - { - return this->m_var >= arg.m_var; - } - - bool operator<=( const EvalArgs & arg ) const - { - return this->m_var <= arg.m_var; - } - - EvalArgs & operator+=( const T & arg ) - { - this->m_var += arg; - return *this; - } - - EvalArgs & operator-=( const T & arg ) - { - this->m_var -= arg; - return *this; - } - - EvalArgs & operator*=( const T & arg ) - { - for( localIndex i = 0; i < Dim; ++i ) - { - this->m_der[i] *= arg; - } - - this->m_var *= arg; - return *this; - } - - EvalArgs & operator/=( const T & arg ) - { - for( localIndex i = 0; i < Dim; ++i ) - { - this->m_der[i] /= arg; - } - - this->m_var /= arg; - return *this; - } - - EvalArgs operator+( const T & arg ) const - { - EvalArgs result( *this ); - result += arg; - return result; - } - - EvalArgs operator-( const T & arg ) const - { - EvalArgs result( *this ); - result -= arg; - return result; - } - - EvalArgs operator*( const T & arg ) const - { - EvalArgs result( *this ); - result *= arg; - return result; - } - - EvalArgs operator/( const T & arg ) const - { - EvalArgs result( *this ); - result /= arg; - return result; - } - - EvalArgs & operator=( const T & arg ) - { - m_var = arg; - for( int i = 0; i < Dim; ++i ) - { - m_der[i] = 0; - } - return *this; - } - - bool operator==( const T & arg ) const - { - return this->m_var == arg; - } - - bool operator!=( const T & arg ) const - { - return !(*this == arg); - } - - bool operator>( const T & arg ) const - { - return this->m_var > arg; - } - - bool operator<( const T & arg ) const - { - return this->m_var < arg; - } - - bool operator>=( const T & arg ) const - { - return this->m_var >= arg; - } - bool operator<=( const T & arg ) const - { - return this->m_var <= arg; - } - - T m_var; - T m_der[Dim]; -}; - -template< class T, int Dim > -inline EvalArgs< T, Dim > operator+( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - EvalArgs< T, Dim > result( arg2 ); - result += arg1; - return result; -} - -template< class T, int Dim > -inline EvalArgs< T, Dim > operator-( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - EvalArgs< T, Dim > result( arg2 ); - result.m_var = arg1 - result.m_var; - - for( localIndex i = 0; i < Dim; ++i ) - { - result.m_der[i] = -result.m_der[i]; - } - - return result; -} - -template< class T, int Dim > -inline EvalArgs< T, Dim > operator*( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - EvalArgs< T, Dim > result( arg2 ); - result *= arg1; - return result; -} - -template< class T, int Dim > -inline EvalArgs< T, Dim > operator/( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - EvalArgs< T, Dim > result( arg2 ); - - T coef = -(arg1 / result.m_var / result.m_var); - result.m_var = arg1 / result.m_var; - - for( localIndex i = 0; i < Dim; ++i ) - { - result.m_der[i] = coef * result.m_der[i]; - } - - return result; -} - - -template< class T, int Dim > -inline bool operator==( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - return (arg2 == arg1); -} - -template< class T, int Dim > -inline bool operator!=( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - return (arg2 != arg1); -} - -template< class T, int Dim > -inline bool operator>( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - return arg1 > arg2.m_var; -} - -template< class T, int Dim > -inline bool operator<( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - return arg1 < arg2.m_var; -} - -template< class T, int Dim > -inline bool operator>=( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - return arg1 >= arg2.m_var; -} - - -template< class T, int Dim > -inline bool operator<=( const T & arg1, const EvalArgs< T, Dim > & arg2 ) -{ - return arg1 <= arg2.m_var; -} - -typedef EvalArgs< real64, 1 > EvalArgs1D; -typedef EvalArgs< real64, 2 > EvalArgs2D; -typedef EvalArgs< real64, 3 > EvalArgs3D; -typedef EvalArgs< real64, MAX_VAR_DIM > EvalVarArgs; - -class TableFunctionBase -{ -public: - virtual const string & tableName() const = 0; - virtual ~TableFunctionBase(){} - - virtual EvalArgs1D value( const EvalArgs1D & x ) const = 0; - - virtual EvalArgs2D value( const EvalArgs2D & x ) const = 0; - - virtual EvalArgs2D value( const EvalArgs2D & x, const EvalArgs2D & y ) const = 0; - - virtual void print() const = 0; -}; - - -typedef std::shared_ptr< TableFunctionBase > TableFunctionPtr; - -class XYTable : public TableFunctionBase -{ -public: - - XYTable( string const & tableName, real64_array const & x, real64_array const & y, real64_array2d const & value ): m_tableName( tableName ), m_x( x ), - m_y( y ), m_value( value ) {} - - ~XYTable(){} - - real64_array & xArray() - { - return m_x; - } - - real64_array & yArray() - { - return m_y; - } - - real64_array2d & valueArray() - { - return m_value; - } - - - virtual string const & tableName() const - { - return m_tableName; - } - - - virtual EvalArgs1D value( EvalArgs1D const & ) const - { - return 0; - } - - virtual EvalArgs2D value( EvalArgs2D const & ) const - { - return 0; - } - - virtual EvalArgs2D value( EvalArgs2D const & x, EvalArgs2D const & y ) const; - - virtual void print() const - {} - -private: - - string m_tableName; - real64_array m_x; - real64_array m_y; - real64_array2d m_value; - -}; - -class XTable : public TableFunctionBase -{ -public: - - XTable( string const & tableName, real64_array const & x, real64_array const & value ): m_tableName( tableName ), m_x( x ), m_value( value ) {} - ~XTable(){} - - real64_array & xArray() - { - return m_x; - } - - real64_array & valueArray() - { - return m_value; - } - - virtual string const & tableName() const - { - return m_tableName; - } - - virtual EvalArgs1D value( EvalArgs1D const & x ) const - { - - return getValue< EvalArgs1D >( x ); - - } - - virtual EvalArgs2D value( EvalArgs2D const & x ) const - { - - return getValue< EvalArgs2D >( x ); - - } - - virtual EvalArgs2D value( EvalArgs2D const &, EvalArgs2D const & ) const - { - return 0; - } - -private: - - template< class T > - T getValue( T const & x ) const; - - virtual void print() const - {} - - string m_tableName; - real64_array m_x; - real64_array m_value; - -}; - -} // namespace PVTProps -} // namespace geosx - -#endif //GEOSX_CONSTITUTIVE_FLUID_PVTFUNCTIONS_UTILITYFUNCTION_HPP_ diff --git a/src/coreComponents/constitutive/fluid/multiFluidSelector.hpp b/src/coreComponents/constitutive/fluid/multiFluidSelector.hpp index b96302b2571..ea8c625ba7c 100644 --- a/src/coreComponents/constitutive/fluid/multiFluidSelector.hpp +++ b/src/coreComponents/constitutive/fluid/multiFluidSelector.hpp @@ -37,7 +37,7 @@ void constitutiveUpdatePassThru( MultiFluidBase const & fluid, ConstitutivePassThruHandler< DeadOilFluid, BlackOilFluid, CompositionalMultiphaseFluid, - MultiPhaseMultiComponentFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) ); + CO2BrineFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) ); } template< typename LAMBDA > @@ -47,7 +47,7 @@ void constitutiveUpdatePassThru( MultiFluidBase & fluid, ConstitutivePassThruHandler< DeadOilFluid, BlackOilFluid, CompositionalMultiphaseFluid, - MultiPhaseMultiComponentFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) ); + CO2BrineFluid >::execute( fluid, std::forward< LAMBDA >( lambda ) ); } } // namespace constitutive diff --git a/src/coreComponents/constitutive/unitTests/CMakeLists.txt b/src/coreComponents/constitutive/unitTests/CMakeLists.txt index 6bb1f2d7602..8fb06292c06 100644 --- a/src/coreComponents/constitutive/unitTests/CMakeLists.txt +++ b/src/coreComponents/constitutive/unitTests/CMakeLists.txt @@ -9,6 +9,8 @@ set( gtest_geosx_tests testElasticIsotropic.cpp testPropertyConversions.cpp testRelPerm.cpp + testCapillaryPressure.cpp + testCO2BrinePVTModels.cpp ) set( dependencyList gtest ) diff --git a/src/coreComponents/constitutive/unitTests/testCO2BrinePVTModels.cpp b/src/coreComponents/constitutive/unitTests/testCO2BrinePVTModels.cpp new file mode 100644 index 00000000000..c5bf46ab2df --- /dev/null +++ b/src/coreComponents/constitutive/unitTests/testCO2BrinePVTModels.cpp @@ -0,0 +1,807 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2018-2020 Total, S.A + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +// Source includes +#include "codingUtilities/UnitTestUtilities.hpp" +#include "common/DataTypes.hpp" +#include "common/TimingMacros.hpp" +#include "constitutive/fluid/multiFluidSelector.hpp" +#include "constitutive/fluid/PVTFunctions/BrineViscosity.hpp" +#include "constitutive/fluid/PVTFunctions/FenghourCO2Viscosity.hpp" +#include "constitutive/fluid/PVTFunctions/BrineCO2Density.hpp" +#include "constitutive/fluid/PVTFunctions/SpanWagnerCO2Density.hpp" +#include "constitutive/fluid/PVTFunctions/CO2Solubility.hpp" +#include "managers/GeosxState.hpp" +#include "managers/initialization.hpp" + +// TPL includes +#include + +using namespace geosx; +using namespace geosx::testing; +using namespace geosx::constitutive; +using namespace geosx::dataRepository; +using namespace geosx::stringutilities; +using namespace geosx::constitutive::PVTProps; + +/// Input tables written into temporary files during testing + +static const char * pvtLiquidTableContent = "DensityFun BrineCO2Density 1e6 1.5e7 5e4 94 96 1 0.2\n" + "ViscosityFun BrineViscosity 0.1"; + +static const char * pvtGasTableContent = "DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 94 96 1\n" + "ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 94 96 1"; + +static const char * co2FlashTableContent = "FlashModel CO2Solubility 1e6 1.5e7 5e4 94 96 1 0.15"; + +void testValuesAgainstPreviousImplementation( PVTFunctionBaseUpdate const & pvtFunctionWrapper, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 > const & phaseComposition, + real64 const & oldImplValue, + bool const useMass, + real64 const relTol ) +{ + real64 value = 0.0; + real64 dValue_dPressure = 0.0; + real64 dValue_dTemperature = 0.0; + stackArray1d< real64, 2 > dPhaseComposition_dPressure( 2 ); + stackArray1d< real64, 2 > dPhaseComposition_dTemperature( 2 ); + stackArray2d< real64, 4 > dPhaseComposition_dGlobalCompFraction( 2, 2 ); + stackArray1d< real64, 2 > dValue_dGlobalCompFraction( 2 ); + pvtFunctionWrapper.compute( pressure, + temperature, + phaseComposition, + dPhaseComposition_dPressure, + dPhaseComposition_dTemperature, + dPhaseComposition_dGlobalCompFraction, + value, + dValue_dPressure, + dValue_dTemperature, + dValue_dGlobalCompFraction, + useMass ); + + checkRelativeError( value, oldImplValue, relTol ); +} + +void testValuesAgainstPreviousImplementation( FlashModelBaseUpdate const & flashModelWrapper, + real64 const & pressure, + real64 const & temperature, + arraySlice1d< real64 > const & compFraction, + real64 const & savedGasPhaseFrac, + real64 const & savedWaterPhaseGasComp, + real64 const relTol ) +{ + stackArray1d< real64, 2 > phaseFraction( 2 ); + stackArray1d< real64, 2 > dPhaseFraction_dPres( 2 ); + stackArray1d< real64, 2 > dPhaseFraction_dTemp( 2 ); + stackArray2d< real64, 4 > dPhaseFraction_dCompFraction( 2, 2 ); + stackArray2d< real64, 4 > phaseCompFraction( 2, 2 ); + stackArray2d< real64, 4 > dPhaseCompFraction_dPres( 2, 2 ); + stackArray2d< real64, 4 > dPhaseCompFraction_dTemp( 2, 2 ); + stackArray3d< real64, 8 > dPhaseCompFraction_dCompFraction( 2, 2, 2 ); + flashModelWrapper.compute( pressure, + temperature, + compFraction, + phaseFraction, + dPhaseFraction_dPres, + dPhaseFraction_dTemp, + dPhaseFraction_dCompFraction, + phaseCompFraction, + dPhaseCompFraction_dPres, + dPhaseCompFraction_dTemp, + dPhaseCompFraction_dCompFraction ); + + for( localIndex i = 0; i < 2; ++i ) + { + real64 const savedPhaseFrac = (i == 0) ? savedGasPhaseFrac : 1.0 - savedGasPhaseFrac; + checkRelativeError( phaseFraction[i], savedPhaseFrac, relTol ); + + for( localIndex j = 0; j < 2; ++j ) + { + real64 savedCompFrac = 0.0; + if( i == 0 ) + { + savedCompFrac = ( j == 0 ) ? 1 : 0; + } + else + { + savedCompFrac = ( j == 0 ) ? savedWaterPhaseGasComp : 1 - savedWaterPhaseGasComp; + } + checkRelativeError( phaseCompFraction[i][j], savedCompFrac, relTol ); + } + } +} + +void testNumericalDerivatives( PVTFunctionBaseUpdate const & pvtFunctionWrapper, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 > const & phaseComposition, + bool const useMass, + real64 const perturbParameter, + real64 const relTol ) +{ + // 1) First compute the unperturbed pressure + real64 value = 0.0; + real64 dValue_dPressure = 0.0; + real64 dValue_dTemperature = 0.0; + stackArray1d< real64, 2 > dPhaseComposition_dPressure( 2 ); + stackArray1d< real64, 2 > dPhaseComposition_dTemperature( 2 ); + stackArray2d< real64, 4 > dPhaseComposition_dGlobalCompFraction( 2, 2 ); + stackArray1d< real64, 2 > dValue_dGlobalCompFraction( 2 ); + dPhaseComposition_dGlobalCompFraction[0][0] = 1.0; + dPhaseComposition_dGlobalCompFraction[1][1] = 1.0; + pvtFunctionWrapper.compute( pressure, + temperature, + phaseComposition, + dPhaseComposition_dPressure, + dPhaseComposition_dTemperature, + dPhaseComposition_dGlobalCompFraction, + value, + dValue_dPressure, + dValue_dTemperature, + dValue_dGlobalCompFraction, + useMass ); + real64 perturbedValue = 0.0; + real64 dPerturbedValue_dPressure = 0.0; + real64 dPerturbedValue_dTemperature = 0.0; + stackArray1d< real64, 2 > dPerturbedValue_dGlobalCompFraction( 2 ); + + // 2) Check derivative with respect to pressure + real64 const dP = perturbParameter * (pressure + perturbParameter); + pvtFunctionWrapper.compute( pressure + dP, + temperature, + phaseComposition, + dPhaseComposition_dPressure, + dPhaseComposition_dTemperature, + dPhaseComposition_dGlobalCompFraction, + perturbedValue, + dPerturbedValue_dPressure, + dPerturbedValue_dTemperature, + dPerturbedValue_dGlobalCompFraction, + useMass ); + checkRelativeError( (perturbedValue-value)/dP, dValue_dPressure, relTol ); + + // 3) Check derivative with respect to temperature + real64 const dT = perturbParameter * (temperature + perturbParameter); + pvtFunctionWrapper.compute( pressure, + temperature + dT, + phaseComposition, + dPhaseComposition_dPressure, + dPhaseComposition_dTemperature, + dPhaseComposition_dGlobalCompFraction, + perturbedValue, + dPerturbedValue_dPressure, + dPerturbedValue_dTemperature, + dPerturbedValue_dGlobalCompFraction, + useMass ); + checkRelativeError( (perturbedValue-value)/dT, dValue_dTemperature, relTol ); + + // 4) Check derivatives with respect to phaseComposition + for( localIndex i = 0; i < 2; ++i ) + { + real64 const dC = perturbParameter * (phaseComposition[i] + perturbParameter); + stackArray1d< real64, 2 > perturbedPhaseComposition( 2 ); + for( localIndex j = 0; j < 2; ++j ) + { + perturbedPhaseComposition[j] = phaseComposition[j] + ( (i == j) ? dC : 0.0 ); + } + pvtFunctionWrapper.compute( pressure, + temperature, + perturbedPhaseComposition, + dPhaseComposition_dPressure, + dPhaseComposition_dTemperature, + dPhaseComposition_dGlobalCompFraction, + perturbedValue, + dPerturbedValue_dPressure, + dPerturbedValue_dTemperature, + dPerturbedValue_dGlobalCompFraction, + useMass ); + checkRelativeError( (perturbedValue-value)/dC, dValue_dGlobalCompFraction[i], relTol ); + } +} + +void testNumericalDerivatives( FlashModelBaseUpdate const & flashModelWrapper, + real64 const pressure, + real64 const temperature, + arraySlice1d< real64 > const & compFraction, + real64 const perturbParameter, + real64 const relTol ) +{ + // 1) First compute the unperturbed pressure + stackArray1d< real64, 2 > phaseFraction( 2 ); + stackArray1d< real64, 2 > dPhaseFraction_dPres( 2 ); + stackArray1d< real64, 2 > dPhaseFraction_dTemp( 2 ); + stackArray2d< real64, 4 > dPhaseFraction_dCompFraction( 2, 2 ); + stackArray2d< real64, 4 > phaseCompFraction( 2, 2 ); + stackArray2d< real64, 4 > dPhaseCompFraction_dPres( 2, 2 ); + stackArray2d< real64, 4 > dPhaseCompFraction_dTemp( 2, 2 ); + stackArray3d< real64, 8 > dPhaseCompFraction_dCompFraction( 2, 2, 2 ); + flashModelWrapper.compute( pressure, + temperature, + compFraction, + phaseFraction, + dPhaseFraction_dPres, + dPhaseFraction_dTemp, + dPhaseFraction_dCompFraction, + phaseCompFraction, + dPhaseCompFraction_dPres, + dPhaseCompFraction_dTemp, + dPhaseCompFraction_dCompFraction ); + stackArray1d< real64, 2 > perturbedPhaseFraction( 2 ); + stackArray1d< real64, 2 > dPerturbedPhaseFraction_dPres( 2 ); + stackArray1d< real64, 2 > dPerturbedPhaseFraction_dTemp( 2 ); + stackArray2d< real64, 4 > dPerturbedPhaseFraction_dCompFraction( 2, 2 ); + stackArray2d< real64, 4 > perturbedPhaseCompFraction( 2, 2 ); + stackArray2d< real64, 4 > dPerturbedPhaseCompFraction_dPres( 2, 2 ); + stackArray2d< real64, 4 > dPerturbedPhaseCompFraction_dTemp( 2, 2 ); + stackArray3d< real64, 8 > dPerturbedPhaseCompFraction_dCompFraction( 2, 2, 2 ); + + // 2) Check derivative with respect to pressure + real64 const dP = perturbParameter * (pressure + perturbParameter); + flashModelWrapper.compute( pressure + dP, + temperature, + compFraction, + perturbedPhaseFraction, + dPerturbedPhaseFraction_dPres, + dPerturbedPhaseFraction_dTemp, + dPerturbedPhaseFraction_dCompFraction, + perturbedPhaseCompFraction, + dPerturbedPhaseCompFraction_dPres, + dPerturbedPhaseCompFraction_dTemp, + dPerturbedPhaseCompFraction_dCompFraction ); + for( localIndex i = 0; i < 2; ++i ) + { + checkRelativeError( (perturbedPhaseFraction[i]-phaseFraction[i])/dP, dPhaseFraction_dPres[i], relTol ); + for( localIndex j = 0; j < 2; ++j ) + { + checkRelativeError( (perturbedPhaseCompFraction[i][j]-phaseCompFraction[i][j])/dP, dPhaseCompFraction_dPres[i][j], relTol ); + } + } + + // 3) Check derivative with respect to temperature + real64 const dT = perturbParameter * (temperature + perturbParameter); + flashModelWrapper.compute( pressure, + temperature + dT, + compFraction, + perturbedPhaseFraction, + dPerturbedPhaseFraction_dPres, + dPerturbedPhaseFraction_dTemp, + dPerturbedPhaseFraction_dCompFraction, + perturbedPhaseCompFraction, + dPerturbedPhaseCompFraction_dPres, + dPerturbedPhaseCompFraction_dTemp, + dPerturbedPhaseCompFraction_dCompFraction ); + for( localIndex i = 0; i < 2; ++i ) + { + checkRelativeError( (perturbedPhaseFraction[i]-phaseFraction[i])/dT, dPhaseFraction_dTemp[i], relTol ); + for( localIndex j = 0; j < 2; ++j ) + { + checkRelativeError( (perturbedPhaseCompFraction[i][j]-phaseCompFraction[i][j])/dT, dPhaseCompFraction_dTemp[i][j], relTol ); + } + } + + // 4) Check derivatives with respect to phaseComposition + for( localIndex i = 0; i < 2; ++i ) + { + real64 const dC = perturbParameter * (compFraction[i] + perturbParameter); + stackArray1d< real64, 2 > perturbedCompFraction( 2 ); + for( localIndex j = 0; j < 2; ++j ) + { + perturbedCompFraction[j] = compFraction[j] + ( (i == j) ? dC : 0.0 ); + } + flashModelWrapper.compute( pressure, + temperature, + perturbedCompFraction, + perturbedPhaseFraction, + dPerturbedPhaseFraction_dPres, + dPerturbedPhaseFraction_dTemp, + dPerturbedPhaseFraction_dCompFraction, + perturbedPhaseCompFraction, + dPerturbedPhaseCompFraction_dPres, + dPerturbedPhaseCompFraction_dTemp, + dPerturbedPhaseCompFraction_dCompFraction ); + for( localIndex j = 0; j < 2; ++j ) + { + checkRelativeError( (perturbedPhaseFraction[j]-phaseFraction[j])/dC, dPhaseFraction_dCompFraction[j][i], relTol ); + for( localIndex k = 0; k < 2; ++k ) + { + checkRelativeError( (perturbedPhaseCompFraction[j][k]-phaseCompFraction[j][k])/dC, dPhaseCompFraction_dCompFraction[j][k][i], relTol ); + } + } + } + +} + +void writeTableToFile( string const & filename, char const * str ) +{ + std::ofstream os( filename ); + ASSERT_TRUE( os.is_open() ); + os << str; + os.close(); +} + +void removeFile( string const & filename ) +{ + int const ret = std::remove( filename.c_str() ); + ASSERT_TRUE( ret == 0 ); +} + +template< typename MODEL > +std::unique_ptr< MODEL > makePVTFunction( string const & filename, + string const & key ) +{ + // define component names and molar weight + string_array componentNames; + componentNames.resize( 2 ); + componentNames[0] = "co2"; componentNames[1] = "water"; + + array1d< real64 > componentMolarWeight; + componentMolarWeight.resize( 2 ); + componentMolarWeight[0] = 44e-3; componentMolarWeight[1] = 18e-3; + + // read parameters from file + std::ifstream is( filename ); + + constexpr std::streamsize buf_size = 256; + char buf[buf_size]; + + std::unique_ptr< MODEL > pvtFunction = nullptr; + + while( is.getline( buf, buf_size )) + { + string const str( buf ); + string_array const strs = stringutilities::tokenize( str, " " ); + + if( strs[0] == key ) + { + pvtFunction = std::make_unique< MODEL >( strs, + componentNames, + componentMolarWeight ); + } + } + GEOSX_ERROR_IF( pvtFunction == nullptr, + "Could not find " << key << " in " << filename ); + + return pvtFunction; +} + +template< typename MODEL > +std::unique_ptr< MODEL > makeFlashModel( string const & filename, + string const & key ) +{ + // define phase names + string_array phaseNames; + phaseNames.resize( 2 ); + phaseNames[0] = "gas"; phaseNames[1] = "liquid"; + + // define component names and molar weight + string_array componentNames; + componentNames.resize( 2 ); + componentNames[0] = "co2"; componentNames[1] = "water"; + + array1d< real64 > componentMolarWeight; + componentMolarWeight.resize( 2 ); + componentMolarWeight[0] = 44e-3; componentMolarWeight[1] = 18e-3; + + // read parameters from file + std::ifstream is( filename ); + + constexpr std::streamsize buf_size = 256; + char buf[buf_size]; + + std::unique_ptr< MODEL > flashModel = nullptr; + + while( is.getline( buf, buf_size )) + { + string const str( buf ); + string_array const strs = stringutilities::tokenize( str, " " ); + + if( strs[0] == key ) + { + flashModel = std::make_unique< MODEL >( strs, + phaseNames, + componentNames, + componentMolarWeight ); + } + } + GEOSX_ERROR_IF( flashModel == nullptr, + "Could not find " << key << " in " << filename ); + + return flashModel; +} + + +class BrineViscosityTest : public ::testing::Test +{ +public: + BrineViscosityTest() + { + writeTableToFile( filename, pvtLiquidTableContent ); + pvtFunction = makePVTFunction< BrineViscosity >( filename, key ); + } + + ~BrineViscosityTest() + { + removeFile( filename ); + } + +protected: + string const key = "ViscosityFun"; + string const filename = "pvtliquid.txt"; + std::unique_ptr< BrineViscosity > pvtFunction; +}; + +TEST_F( BrineViscosityTest, brineViscosityValuesAndDeriv ) +{ + real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; + real64 const TC[3] = { 94.5, 95, 95.6 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.304; comp[1] = 0.696; + real64 const deltaComp = 0.2; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 5e-5; + + real64 const savedValues[] = { 0.0009009475991, 0.0009009665224, 0.0009009892304, 0.0009009475991, 0.0009009665224, + 0.0009009892304, 0.0009009475991, 0.0009009665224, 0.0009009892304, 0.0009009475991, + 0.0009009665224, 0.0009009892304, 0.0009009475991, 0.0009009665224, 0.0009009892304, + 0.0009009475991, 0.0009009665224, 0.0009009892304, 0.0009009475991, 0.0009009665224, + 0.0009009892304, 0.0009009475991, 0.0009009665224, 0.0009009892304, 0.0009009475991, + 0.0009009665224, 0.0009009892304 }; + + BrineViscosity::KernelWrapper pvtFunctionWrapper = pvtFunction->createKernelWrapper(); + + localIndex counter = 0; + for( localIndex iComp = 0; iComp < 3; ++iComp ) + { + for( localIndex iPres = 0; iPres < 3; ++iPres ) + { + for( localIndex iTemp = 0; iTemp < 3; ++iTemp ) + { + testValuesAgainstPreviousImplementation( pvtFunctionWrapper, + P[iPres], TC[iTemp], comp, savedValues[counter], true, relTol ); + testNumericalDerivatives( pvtFunctionWrapper, P[iPres], TC[iTemp], comp, true, eps, relTol ); + counter++; + } + } + comp[0] += deltaComp; + comp[1] = 1 - comp[0]; + } +} + +class FenghourCO2ViscosityTest : public ::testing::Test +{ +public: + FenghourCO2ViscosityTest() + { + writeTableToFile( filename, pvtGasTableContent ); + pvtFunction = makePVTFunction< FenghourCO2Viscosity >( filename, key ); + } + + ~FenghourCO2ViscosityTest() + { + removeFile( filename ); + } + +protected: + string const key = "ViscosityFun"; + string const filename = "pvtgas.txt"; + std::unique_ptr< FenghourCO2Viscosity > pvtFunction; +}; + +TEST_F( FenghourCO2ViscosityTest, fenghourCO2ViscosityValuesAndDeriv ) +{ + // when checking numerical derivatives, do not fall on the coordinate points of the tables!! + // (see the txt file defined at the top of the file for the definition of the coordinates) + real64 const P[3] = { 5.012e6, 7.546e6, 1.289e7 }; + real64 const TC[3] = { 94.5, 95.1, 95.6 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.304; comp[1] = 0.696; + real64 const deltaComp = 0.2; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 5e-5; + + real64 const savedValues[] = { 1.904605302e-05, 1.907031467e-05, 1.909055363e-05, 2.008611673e-05, 2.010303796e-05, 2.011728461e-05, + 2.508888392e-05, 2.504245053e-05, 2.500575965e-05, 1.904605302e-05, 1.907031467e-05, 1.909055363e-05, + 2.008611673e-05, 2.010303796e-05, 2.011728461e-05, 2.508888392e-05, 2.504245053e-05, 2.500575965e-05, + 1.904605302e-05, 1.907031467e-05, 1.909055363e-05, 2.008611673e-05, 2.010303796e-05, 2.011728461e-05, + 2.508888392e-05, 2.504245053e-05, 2.500575965e-05 }; + + FenghourCO2Viscosity::KernelWrapper pvtFunctionWrapper = pvtFunction->createKernelWrapper(); + + localIndex counter = 0; + for( localIndex iComp = 0; iComp < 3; ++iComp ) + { + for( localIndex iPres = 0; iPres < 3; ++iPres ) + { + for( localIndex iTemp = 0; iTemp < 3; ++iTemp ) + { + testValuesAgainstPreviousImplementation( pvtFunctionWrapper, + P[iPres], TC[iTemp], comp, savedValues[counter], true, relTol ); + testNumericalDerivatives( pvtFunctionWrapper, P[iPres], TC[iTemp], comp, true, eps, relTol ); + counter++; + } + } + comp[0] += deltaComp; + comp[1] = 1 - comp[0]; + } +} + +class BrineCO2DensityTest : public ::testing::Test +{ +public: + BrineCO2DensityTest() + { + writeTableToFile( filename, pvtLiquidTableContent ); + pvtFunction = makePVTFunction< BrineCO2Density >( filename, key ); + } + + ~BrineCO2DensityTest() + { + removeFile( filename ); + } + +protected: + string const key = "DensityFun"; + string const filename = "pvtliquid.txt"; + std::unique_ptr< BrineCO2Density > pvtFunction; +}; + +TEST_F( BrineCO2DensityTest, brineCO2DensityMassValuesAndDeriv ) +{ + // when checking numerical derivatives, do not fall on the coordinate points of the tables!! + // (see the txt file defined at the top of the file for the definition of the coordinates) + real64 const P[3] = { 5.012e6, 7.546e6, 1.289e7 }; + real64 const TC[3] = { 94.5, 95.1, 95.6 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.304; comp[1] = 0.696; + real64 const deltaComp = 0.2; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 5e-5; + + real64 const savedValues[] = { 1186.281618, 1185.321099, 1184.511961, 1186.997612, 1186.037426, 1185.228539, 1188.470081, 1187.510437, + 1186.70195, 1477.603717, 1476.040357, 1474.719028, 1476.803422, 1475.235146, 1473.909633, 1475.091089, + 1473.51237, 1472.177974, 2162.60433, 2159.623476, 2157.097807, 2158.238706, 2155.240595, 2152.700314, + 2149.037782, 2146.003403, 2143.432409 }; + + BrineCO2Density::KernelWrapper pvtFunctionWrapper = pvtFunction->createKernelWrapper(); + + localIndex counter = 0; + for( localIndex iComp = 0; iComp < 3; ++iComp ) + { + for( localIndex iPres = 0; iPres < 3; ++iPres ) + { + for( localIndex iTemp = 0; iTemp < 3; ++iTemp ) + { + testValuesAgainstPreviousImplementation( pvtFunctionWrapper, + P[iPres], TC[iTemp], comp, savedValues[counter], true, relTol ); + testNumericalDerivatives( pvtFunctionWrapper, P[iPres], TC[iTemp], comp, true, eps, relTol ); + counter++; + } + } + comp[0] += deltaComp; + comp[1] = 1 - comp[0]; + } +} + +TEST_F( BrineCO2DensityTest, brineCO2DensityMolarValuesAndDeriv ) +{ + // when checking numerical derivatives, do not fall on the coordinate points of the tables!! + // (see the txt file defined at the top of the file for the definition of the coordinates) + real64 const P[3] = { 5.012e6, 7.546e6, 1.289e7 }; + real64 const TC[3] = { 94.5, 95.1, 95.6 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.304; comp[1] = 0.696; + real64 const deltaComp = 0.2; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 5e-5; + + BrineCO2Density::KernelWrapper pvtFunctionWrapper = pvtFunction->createKernelWrapper(); + + localIndex counter = 0; + for( localIndex iComp = 0; iComp < 3; ++iComp ) + { + for( localIndex iPres = 0; iPres < 3; ++iPres ) + { + for( localIndex iTemp = 0; iTemp < 3; ++iTemp ) + { + //testValuesAgainstPreviousImplementation( pvtFunctionWrapper, + // P[iPres], TC[iTemp], comp, savedValues[counter], false, relTol ); + testNumericalDerivatives( pvtFunctionWrapper, P[iPres], TC[iTemp], comp, false, eps, relTol ); + counter++; + } + } + comp[0] += deltaComp; + comp[1] = 1 - comp[0]; + } +} + + +class SpanWagnerCO2DensityTest : public ::testing::Test +{ +public: + SpanWagnerCO2DensityTest() + { + writeTableToFile( filename, pvtGasTableContent ); + pvtFunction = makePVTFunction< SpanWagnerCO2Density >( filename, key ); + } + + ~SpanWagnerCO2DensityTest() + { + removeFile( filename ); + } + +protected: + string const key = "DensityFun"; + string const filename = "pvtgas.txt"; + std::unique_ptr< SpanWagnerCO2Density > pvtFunction; +}; + +TEST_F( SpanWagnerCO2DensityTest, spanWagnerCO2DensityMassValuesAndDeriv ) +{ + // when checking numerical derivatives, do not fall on the coordinate points of the tables!! + // (see the txt file defined at the top of the file for the definition of the coordinates) + real64 const P[3] = { 5.012e6, 7.546e6, 1.289e7 }; + real64 const TC[3] = { 94.5, 95.1, 95.6 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.304; comp[1] = 0.696; + real64 const deltaComp = 0.2; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 5e-5; + + real64 const savedValues[] = { 82.78363562, 82.56888654, 82.39168811, 135.3774839, 134.9199659, 134.5440568, 281.9140962, 280.2559694, + 278.9092508, 82.78363562, 82.56888654, 82.39168811, 135.3774839, 134.9199659, 134.5440568, 281.9140962, + 280.2559694, 278.9092508, 82.78363562, 82.56888654, 82.39168811, 135.3774839, 134.9199659, 134.5440568, + 281.9140962, 280.2559694, 278.9092508 }; + + SpanWagnerCO2Density::KernelWrapper pvtFunctionWrapper = pvtFunction->createKernelWrapper(); + + localIndex counter = 0; + for( localIndex iComp = 0; iComp < 3; ++iComp ) + { + for( localIndex iPres = 0; iPres < 3; ++iPres ) + { + for( localIndex iTemp = 0; iTemp < 3; ++iTemp ) + { + testValuesAgainstPreviousImplementation( pvtFunctionWrapper, + P[iPres], TC[iTemp], comp, savedValues[counter], true, relTol ); + testNumericalDerivatives( pvtFunctionWrapper, P[iPres], TC[iTemp], comp, true, eps, relTol ); + counter++; + } + } + comp[0] += deltaComp; + comp[1] = 1 - comp[0]; + } +} + +TEST_F( SpanWagnerCO2DensityTest, spanWagnerCO2DensityMolarValuesAndDeriv ) +{ + // when checking numerical derivatives, do not fall on the coordinate points of the tables!! + // (see the txt file defined at the top of the file for the definition of the coordinates) + real64 const P[3] = { 5.012e6, 7.546e6, 1.289e7 }; + real64 const TC[3] = { 94.5, 95.1, 95.6 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.304; comp[1] = 0.696; + real64 const deltaComp = 0.2; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 5e-5; + + real64 const savedValues[] = { 1881.446264, 1876.565603, 1872.538366, 3076.760999, 3066.362862, 3057.819473, 6407.138549, 6369.45385, + 6338.846609, 1881.446264, 1876.565603, 1872.538366, 3076.760999, 3066.362862, 3057.819473, 6407.138549, + 6369.45385, 6338.846609, 1881.446264, 1876.565603, 1872.538366, 3076.760999, 3066.362862, 3057.819473, + 6407.138549, 6369.45385, 6338.846609 }; + + SpanWagnerCO2Density::KernelWrapper pvtFunctionWrapper = pvtFunction->createKernelWrapper(); + + localIndex counter = 0; + for( localIndex iComp = 0; iComp < 3; ++iComp ) + { + for( localIndex iPres = 0; iPres < 3; ++iPres ) + { + for( localIndex iTemp = 0; iTemp < 3; ++iTemp ) + { + testValuesAgainstPreviousImplementation( pvtFunctionWrapper, + P[iPres], TC[iTemp], comp, savedValues[counter], false, relTol ); + testNumericalDerivatives( pvtFunctionWrapper, P[iPres], TC[iTemp], comp, false, eps, relTol ); + counter++; + } + } + comp[0] += deltaComp; + comp[1] = 1 - comp[0]; + } +} + + +class CO2SolubilityTest : public ::testing::Test +{ +public: + CO2SolubilityTest() + { + writeTableToFile( filename, co2FlashTableContent ); + flashModel = makeFlashModel< CO2Solubility >( filename, key ); + } + + ~CO2SolubilityTest() + { + removeFile( filename ); + } + +protected: + string const key = "FlashModel"; + string const filename = "co2flash.txt"; + std::unique_ptr< CO2Solubility > flashModel; +}; + +TEST_F( CO2SolubilityTest, co2SolubilityValuesAndDeriv ) +{ + // when checking numerical derivatives, do not fall on the coordinate points of the tables!! + // (see the txt file defined at the top of the file for the definition of the coordinates) + real64 const P[3] = { 5.012e6, 7.546e6, 1.289e7 }; + real64 const TC[3] = { 94.5, 95.1, 95.6 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.304; comp[1] = 0.696; + real64 const deltaComp = 0.2; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 5e-5; + + real64 const savedGasPhaseFrac[] = { 0.298158785, 0.298183347, 0.2982033821, 0.295950309, 0.2959791448, 0.2960026365, 0.2926988393, + 0.292724834, 0.2927459702, 0.499837295, 0.499854799, 0.4998690769, 0.4982634386, 0.4982839883, + 0.4983007295, 0.4959462993, 0.4959648242, 0.4959798868, 0.7015158051, 0.701526251, 0.7015347717, + 0.7005765682, 0.7005888317, 0.7005988224, 0.6991937592, 0.6992048145, 0.6992138034 }; + real64 const savedWaterPhaseGasComp[] = { 0.008322701666, 0.008287995083, 0.008259683449, 0.01143341315, 0.0113929227, 0.01135993384, + 0.01597786252, 0.01594169644, 0.015912288, 0.008322701666, 0.008287995083, 0.008259683449, + 0.01143341315, 0.0113929227, 0.01135993384, 0.01597786252, 0.01594169644, 0.015912288, + 0.008322701666, 0.008287995083, 0.008259683449, 0.01143341315, 0.0113929227, 0.01135993384, + 0.01597786252, 0.01594169644, 0.015912288 }; + + CO2Solubility::KernelWrapper flashModelWrapper = flashModel->createKernelWrapper(); + + localIndex counter = 0; + for( localIndex iComp = 0; iComp < 3; ++iComp ) + { + for( localIndex iPres = 0; iPres < 3; ++iPres ) + { + for( localIndex iTemp = 0; iTemp < 3; ++iTemp ) + { + testValuesAgainstPreviousImplementation( flashModelWrapper, + P[iPres], TC[iTemp], comp, + savedGasPhaseFrac[counter], savedWaterPhaseGasComp[counter], relTol ); + testNumericalDerivatives( flashModelWrapper, P[iPres], TC[iTemp], comp, eps, relTol ); + counter++; + } + } + comp[0] += deltaComp; + comp[1] = 1 - comp[0]; + } +} + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + + geosx::GeosxState state( geosx::basicSetup( argc, argv ) ); + + int const result = RUN_ALL_TESTS(); + + geosx::basicCleanup(); + + return result; +} diff --git a/src/coreComponents/constitutive/unitTests/testMultiFluid.cpp b/src/coreComponents/constitutive/unitTests/testMultiFluid.cpp index 547b1301b83..b8bac1bbe93 100644 --- a/src/coreComponents/constitutive/unitTests/testMultiFluid.cpp +++ b/src/coreComponents/constitutive/unitTests/testMultiFluid.cpp @@ -22,7 +22,6 @@ #include "managers/Functions/FunctionManager.hpp" #include "managers/GeosxState.hpp" - // TPL includes #include #include @@ -31,84 +30,95 @@ using namespace geosx; using namespace geosx::testing; using namespace geosx::constitutive; using namespace geosx::dataRepository; +using namespace geosx::constitutive::PVTProps; /// Black-oil tables written into temporary files during testing -static const char * pvtg_str = "#\tPg(Pa)\t\tRv(sm3/sm3)\tBg(m3/sm3)\tVisc(Pa.s)\n" - "\n" - "\t3000000\t\t0.000132\t0.04234\t 0.00001344\n" - "\t\t\t\t0\t\t\t0.04231\t 0.00001389\n" - "\t6000000\t\t0.000124\t0.02046\t 0.0000142\n" - "\t\t\t\t0\t\t\t0.02043\t 0.0000145\n" - "\t9000000\t\t0.000126\t0.01328\t 0.00001526\n" - "\t\t\t\t0\t\t\t0.01325\t 0.00001532\n" - " 12000000\t\t0.000135\t0.00977\t 0.0000166\n" - "\t\t\t\t0\t\t\t0.00973\t 0.00001634\n" - " 15000000\t\t0.000149\t0.00773\t 0.00001818\n" - "\t\t\t\t0\t\t\t0.00769\t 0.00001752\n" - " 18000000\t\t0.000163\t0.006426\t0.00001994\n" - "\t\t\t\t0\t\t\t0.006405\t0.00001883\n" - " 21000000\t\t0.000191\t0.005541\t0.00002181\n" - "\t\t\t\t0\t\t\t0.005553\t0.00002021\n" - " 24000000\t\t0.000225\t0.004919\t0.0000237\n" - "\t\t\t\t0\t\t\t0.004952\t0.00002163\n" - " 27000000\t\t0.000272\t0.004471\t0.00002559\n" - "\t\t\t\t0\t\t\t0.004511\t0.00002305\n" - " 29500000\t\t0.000354\t0.004194\t0.00002714\n" - "\t\t\t\t0\t\t\t0.004225\t0.00002423\n" - " 31000000\t\t0.000403\t0.004031\t0.00002806\n" - "\t\t\t\t0.000354\t0.004059\t0.00002768\n" - " 33000000\t\t0.000354\t0.00391\t 0.00002832\n" - "\t\t\t\t0\t\t\t0.003913\t0.00002583\n" - " 53000000\t\t0.000479\t0.003868\t0.00002935\n" - "\t\t\t\t0.000354\t0.0039\t\t0.00002842\n" - "\t\t\t\t0\t\t\t0.003903\t0.00002593"; - -static const char * pvto_str = "# Rs[sm3/sm3]\tPbub[Pa]\tBo[m3/sm3]\tVisc(Pa.s)\n" - "\n" - " 2\t 2000000\t 1.02\t 0.000975\n" - " 5\t 5000000\t 1.03\t 0.00091\n" - " 10\t 10000000\t1.04\t 0.00083\n" - " 15\t 20000000\t1.05\t 0.000695\n" - " 90000000\t1.03\t 0.000985 -- some line comment\n" - " 30\t 30000000\t1.07\t 0.000594\n" - " 40\t 40000000\t1.08\t 0.00051\n" - " 50000000\t1.07\t 0.000549 -- another one\n" - " 90000000\t1.06\t 0.00074\n" - " 50\t 50000000.7\t1.09\t 0.000449\n" - " 90000000.7\t1.08\t 0.000605"; - -static const char * pvtw_str = "#\tPref[bar]\tBw[m3/sm3]\tCp[1/bar]\t Visc[cP]\n" - "\t30600000.1\t1.03\t\t0.00000000041\t0.0003"; +static const char * pvtgTableContent = "#\tPg(Pa)\t\tRv(sm3/sm3)\tBg(m3/sm3)\tVisc(Pa.s)\n" + "\n" + "\t3000000\t\t0.000132\t0.04234\t 0.00001344\n" + "\t\t\t\t0\t\t\t0.04231\t 0.00001389\n" + "\t6000000\t\t0.000124\t0.02046\t 0.0000142\n" + "\t\t\t\t0\t\t\t0.02043\t 0.0000145\n" + "\t9000000\t\t0.000126\t0.01328\t 0.00001526\n" + "\t\t\t\t0\t\t\t0.01325\t 0.00001532\n" + " 12000000\t\t0.000135\t0.00977\t 0.0000166\n" + "\t\t\t\t0\t\t\t0.00973\t 0.00001634\n" + " 15000000\t\t0.000149\t0.00773\t 0.00001818\n" + "\t\t\t\t0\t\t\t0.00769\t 0.00001752\n" + " 18000000\t\t0.000163\t0.006426\t0.00001994\n" + "\t\t\t\t0\t\t\t0.006405\t0.00001883\n" + " 21000000\t\t0.000191\t0.005541\t0.00002181\n" + "\t\t\t\t0\t\t\t0.005553\t0.00002021\n" + " 24000000\t\t0.000225\t0.004919\t0.0000237\n" + "\t\t\t\t0\t\t\t0.004952\t0.00002163\n" + " 27000000\t\t0.000272\t0.004471\t0.00002559\n" + "\t\t\t\t0\t\t\t0.004511\t0.00002305\n" + " 29500000\t\t0.000354\t0.004194\t0.00002714\n" + "\t\t\t\t0\t\t\t0.004225\t0.00002423\n" + " 31000000\t\t0.000403\t0.004031\t0.00002806\n" + "\t\t\t\t0.000354\t0.004059\t0.00002768\n" + " 33000000\t\t0.000354\t0.00391\t 0.00002832\n" + "\t\t\t\t0\t\t\t0.003913\t0.00002583\n" + " 53000000\t\t0.000479\t0.003868\t0.00002935\n" + "\t\t\t\t0.000354\t0.0039\t\t0.00002842\n" + "\t\t\t\t0\t\t\t0.003903\t0.00002593"; + +static const char * pvtoTableContent = "# Rs[sm3/sm3]\tPbub[Pa]\tBo[m3/sm3]\tVisc(Pa.s)\n" + "\n" + " 2\t 2000000\t 1.02\t 0.000975\n" + " 5\t 5000000\t 1.03\t 0.00091\n" + " 10\t 10000000\t1.04\t 0.00083\n" + " 15\t 20000000\t1.05\t 0.000695\n" + " 90000000\t1.03\t 0.000985 -- some line comment\n" + " 30\t 30000000\t1.07\t 0.000594\n" + " 40\t 40000000\t1.08\t 0.00051\n" + " 50000000\t1.07\t 0.000549 -- another one\n" + " 90000000\t1.06\t 0.00074\n" + " 50\t 50000000.7\t1.09\t 0.000449\n" + " 90000000.7\t1.08\t 0.000605"; + +static const char * pvtwTableContent = "#\tPref[bar]\tBw[m3/sm3]\tCp[1/bar]\t Visc[cP]\n" + "\t30600000.1\t1.03\t\t0.00000000041\t0.0003"; /// Dead-oil tables written into temporary files during testing -static const char * pvdg_str = "# Pg(Pa) Bg(m3/sm3) Visc(Pa.s)\n" - "3000000 0.04234 0.00001344\n" - "6000000 0.02046 0.0000142\n" - "9000000 0.01328 0.00001526\n" - "12000000 0.00977 0.0000166\n" - "15000000 0.00773 0.00001818\n" - "18000000 0.006426 0.00001994\n" - "21000000 0.005541 0.00002181\n" - "24000000 0.004919 0.0000237\n" - "27000000 0.004471 0.00002559\n" - "29500000 0.004194 0.00002714\n" - "31000000 0.004031 0.00002806\n" - "33000000 0.00391 0.00002832\n" - "53000000 0.003868 0.00002935"; - -static const char * pvdo_str = "#P[Pa] Bo[m3/sm3] Visc(Pa.s)\n" - "2000000 1.02 0.000975\n" - "5000000 1.03 0.00091\n" - "10000000 1.04 0.00083\n" - "20000000 1.05 0.000695\n" - "30000000 1.07 0.000594\n" - "40000000 1.08 0.00051\n" - "50000000.7 1.09 0.000449"; - -static const char * pvdw_str = "# Pref[bar] Bw[m3/sm3] Cp[1/bar] Visc[cP]\n" - " 30600000.1 1.03 0.00000000041 0.0003"; +static const char * pvdgTableContent = "# Pg(Pa) Bg(m3/sm3) Visc(Pa.s)\n" + "3000000 0.04234 0.00001344\n" + "6000000 0.02046 0.0000142\n" + "9000000 0.01328 0.00001526\n" + "12000000 0.00977 0.0000166\n" + "15000000 0.00773 0.00001818\n" + "18000000 0.006426 0.00001994\n" + "21000000 0.005541 0.00002181\n" + "24000000 0.004919 0.0000237\n" + "27000000 0.004471 0.00002559\n" + "29500000 0.004194 0.00002714\n" + "31000000 0.004031 0.00002806\n" + "33000000 0.00391 0.00002832\n" + "53000000 0.003868 0.00002935"; + +static const char * pvdoTableContent = "#P[Pa] Bo[m3/sm3] Visc(Pa.s)\n" + "2000000 1.02 0.000975\n" + "5000000 1.03 0.00091\n" + "10000000 1.04 0.00083\n" + "20000000 1.05 0.000695\n" + "30000000 1.07 0.000594\n" + "40000000 1.08 0.00051\n" + "50000000.7 1.09 0.000449"; + +static const char * pvdwTableContent = "# Pref[bar] Bw[m3/sm3] Cp[1/bar] Visc[cP]\n" + " 30600000.1 1.03 0.00000000041 0.0003"; + +// CO2-brine model + +static const char * pvtLiquidTableContent = "DensityFun BrineCO2Density 1e6 1.5e7 5e4 94 96 1 0.2\n" + "ViscosityFun BrineViscosity 0.1"; + +static const char * pvtGasTableContent = "DensityFun SpanWagnerCO2Density 1e6 1.5e7 5e4 94 96 1\n" + "ViscosityFun FenghourCO2Viscosity 1e6 1.5e7 5e4 94 96 1"; + +static const char * co2FlashTableContent = "FlashModel CO2Solubility 1e6 1.5e7 5e4 94 96 1 0.15"; void testNumericalDerivatives( MultiFluidBase & fluid, Group & parent, @@ -116,6 +126,7 @@ void testNumericalDerivatives( MultiFluidBase & fluid, real64 const T, arraySlice1d< real64 > const & composition, real64 const perturbParameter, + bool usePVTPackage, real64 const relTol, real64 const absTol = std::numeric_limits< real64 >::max() ) { @@ -210,7 +221,6 @@ void testNumericalDerivatives( MultiFluidBase & fluid, "Pres", phases, components ); - std::cout << phaseDens.value << std::endl; } // update temperature and check derivatives @@ -251,12 +261,25 @@ void testNumericalDerivatives( MultiFluidBase & fluid, } compNew[jc] += dC; - // renormalize - real64 sum = 0.0; - for( localIndex ic = 0; ic < NC; ++ic ) - sum += compNew[ic]; - for( localIndex ic = 0; ic < NC; ++ic ) - compNew[ic] /= sum; + // Note: in PVTPackage, derivatives are obtained with finite-difference approx **with normalization of the comp fraction** + // The component fraction is perturbed (just as above), and then all the component fractions are normalized (as below) + // But, in the native DO model and in CO2Brine, derivatives are computed analytically, which results in different + // derivatives wrt component fractions--although the derivatives wrt component densities obtained with the chain rule + // in the solver will be very similar (see discussion on PR #1325 on GitHub). + // + // Since both approaches--FD approximation of derivatives with normalization, and analytical derivatives--are correct, + // we have to support both when we check the intermediate derivatives wrt component fractions below. Therefore, if the + // PVTPackage is used, then we normalize the perturbed component fractions before taking the FD approx. If the native + // DO or CO2-brine models are used, we skip the normalization below. + if( usePVTPackage ) + { + // renormalize + real64 sum = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + sum += compNew[ic]; + for( localIndex ic = 0; ic < NC; ++ic ) + compNew[ic] /= sum; + } fluidWrapper.update( 0, 0, P, T, compNew ); @@ -271,6 +294,100 @@ void testNumericalDerivatives( MultiFluidBase & fluid, } ); } +void testValuesAgainstPreviousImplementation( CO2BrineFluid::KernelWrapper const & wrapper, + real64 const P, + real64 const T, + arraySlice1d< real64 > const & composition, + real64 const & savedTotalDensity, + real64 const & savedGasPhaseFrac, + real64 const & savedWaterDens, + real64 const & savedGasDens, + real64 const & savedWaterMassDens, + real64 const & savedGasMassDens, + real64 const & savedWaterVisc, + real64 const & savedGasVisc, + real64 const & savedWaterPhaseGasComp, + real64 const & savedWaterPhaseWaterComp, + real64 const relTol ) +{ + stackArray1d< real64, 2 > phaseFraction( 2 ); + stackArray1d< real64, 2 > dPhaseFraction_dPressure( 2 ); + stackArray1d< real64, 2 > dPhaseFraction_dTemperature( 2 ); + stackArray2d< real64, 4 > dPhaseFraction_dGlobalCompFraction( 2, 2 ); + stackArray1d< real64, 2 > phaseDensity( 2 ); + stackArray1d< real64, 2 > dPhaseDensity_dPressure( 2 ); + stackArray1d< real64, 2 > dPhaseDensity_dTemperature( 2 ); + stackArray2d< real64, 4 > dPhaseDensity_dGlobalCompFraction( 2, 2 ); + stackArray1d< real64, 2 > phaseMassDensity( 2 ); + stackArray1d< real64, 2 > dPhaseMassDensity_dPressure( 2 ); + stackArray1d< real64, 2 > dPhaseMassDensity_dTemperature( 2 ); + stackArray2d< real64, 4 > dPhaseMassDensity_dGlobalCompFraction( 2, 2 ); + stackArray1d< real64, 2 > phaseViscosity( 2 ); + stackArray1d< real64, 2 > dPhaseViscosity_dPressure( 2 ); + stackArray1d< real64, 2 > dPhaseViscosity_dTemperature( 2 ); + stackArray2d< real64, 4 > dPhaseViscosity_dGlobalCompFraction( 2, 2 ); + stackArray2d< real64, 4 > phaseCompFraction( 2, 2 ); + stackArray2d< real64, 4 > dPhaseCompFraction_dPressure( 2, 2 ); + stackArray2d< real64, 4 > dPhaseCompFraction_dTemperature( 2, 2 ); + stackArray3d< real64, 8 > dPhaseCompFraction_dGlobalCompFraction( 2, 2, 2 ); + real64 totalDensity = 0.0; + real64 dTotalDensity_dPressure = 0.0; + real64 dTotalDensity_dTemperature = 0.0; + stackArray1d< real64, 2 > dTotalDensity_dGlobalCompFraction( 2 ); + + wrapper.compute( P, T, composition, + phaseFraction, + dPhaseFraction_dPressure, + dPhaseFraction_dTemperature, + dPhaseFraction_dGlobalCompFraction, + phaseDensity, + dPhaseDensity_dPressure, + dPhaseDensity_dTemperature, + dPhaseDensity_dGlobalCompFraction, + phaseMassDensity, + dPhaseMassDensity_dPressure, + dPhaseMassDensity_dTemperature, + dPhaseMassDensity_dGlobalCompFraction, + phaseViscosity, + dPhaseViscosity_dPressure, + dPhaseViscosity_dTemperature, + dPhaseViscosity_dGlobalCompFraction, + phaseCompFraction, + dPhaseCompFraction_dPressure, + dPhaseCompFraction_dTemperature, + dPhaseCompFraction_dGlobalCompFraction, + totalDensity, + dTotalDensity_dPressure, + dTotalDensity_dTemperature, + dTotalDensity_dGlobalCompFraction ); + + checkRelativeError( totalDensity, savedTotalDensity, relTol ); + for( localIndex ip = 0; ip < 2; ++ip ) + { + real64 const savedPhaseFrac = ( ip == 0 ) ? savedGasPhaseFrac : 1 - savedGasPhaseFrac; + checkRelativeError( phaseFraction[ip], savedPhaseFrac, relTol ); + real64 const savedPhaseDens = ( ip == 0 ) ? savedGasDens : savedWaterDens; + checkRelativeError( phaseDensity[ip], savedPhaseDens, relTol ); + real64 const savedPhaseMassDens = ( ip == 0 ) ? savedGasMassDens : savedWaterMassDens; + checkRelativeError( phaseMassDensity[ip], savedPhaseMassDens, relTol ); + real64 const savedPhaseVisc = ( ip == 0 ) ? savedGasVisc : savedWaterVisc; + checkRelativeError( phaseViscosity[ip], savedPhaseVisc, relTol ); + for( localIndex ic = 0; ic < 2; ++ic ) + { + real64 savedCompFrac = 0.0; + if( ip == 0 ) + { + savedCompFrac = ( ic == 0 ) ? 1 : 0; + } + else + { + savedCompFrac = ( ic == 0 ) ? savedWaterPhaseGasComp : savedWaterPhaseWaterComp; + } + checkRelativeError( phaseCompFraction[ip][ic], savedCompFrac, relTol ); + } + } +} + MultiFluidBase & makeCompositionalFluid( string const & name, Group & parent ) { CompositionalMultiphaseFluid & fluid = parent.registerGroup< CompositionalMultiphaseFluid >( name ); @@ -349,7 +466,7 @@ TEST_F( CompositionalFluidTest, numericalDerivativesMolar ) real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); real64 const relTol = 1e-4; - testNumericalDerivatives( *fluid, parent, P, T, comp, eps, relTol ); + testNumericalDerivatives( *fluid, parent, P, T, comp, eps, true, relTol ); } TEST_F( CompositionalFluidTest, numericalDerivativesMass ) @@ -365,7 +482,7 @@ TEST_F( CompositionalFluidTest, numericalDerivativesMass ) real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); real64 const relTol = 1e-2; - testNumericalDerivatives( *fluid, parent, P, T, comp, eps, relTol ); + testNumericalDerivatives( *fluid, parent, P, T, comp, eps, true, relTol ); } MultiFluidBase & makeLiveOilFluid( string const & name, Group * parent ) @@ -552,9 +669,9 @@ class LiveOilFluidTest : public CompositionalFluidTestBase public: LiveOilFluidTest() { - writeTableToFile( "pvto.txt", pvto_str ); - writeTableToFile( "pvtg.txt", pvtg_str ); - writeTableToFile( "pvtw.txt", pvtw_str ); + writeTableToFile( "pvto.txt", pvtoTableContent ); + writeTableToFile( "pvtg.txt", pvtgTableContent ); + writeTableToFile( "pvtw.txt", pvtwTableContent ); parent.resize( 1 ); fluid = &makeLiveOilFluid( "fluid", &parent ); @@ -584,7 +701,7 @@ TEST_F( LiveOilFluidTest, numericalDerivativesMolar ) real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); real64 const relTol = 1e-4; - testNumericalDerivatives( *fluid, parent, P, T, comp, eps, relTol ); + testNumericalDerivatives( *fluid, parent, P, T, comp, eps, true, relTol ); } TEST_F( LiveOilFluidTest, numericalDerivativesMass ) @@ -601,7 +718,7 @@ TEST_F( LiveOilFluidTest, numericalDerivativesMass ) real64 const relTol = 1e-2; real64 const absTol = 1e-14; - testNumericalDerivatives( *fluid, parent, P, T, comp, eps, relTol, absTol ); + testNumericalDerivatives( *fluid, parent, P, T, comp, eps, true, relTol, absTol ); } class DeadOilFluidTest : public CompositionalFluidTestBase @@ -610,9 +727,9 @@ class DeadOilFluidTest : public CompositionalFluidTestBase DeadOilFluidTest() { - writeTableToFile( "pvdo.txt", pvdo_str ); - writeTableToFile( "pvdg.txt", pvdg_str ); - writeTableToFile( "pvdw.txt", pvdw_str ); + writeTableToFile( "pvdo.txt", pvdoTableContent ); + writeTableToFile( "pvdg.txt", pvdgTableContent ); + writeTableToFile( "pvdw.txt", pvdwTableContent ); parent.resize( 1 ); fluid = &makeDeadOilFluid( "fluid", &parent ); @@ -643,7 +760,7 @@ TEST_F( DeadOilFluidTest, numericalDerivativesMolar ) for( localIndex i = 0; i < 3; ++i ) { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, relTol ); + testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol ); } } @@ -662,7 +779,7 @@ TEST_F( DeadOilFluidTest, numericalDerivativesMass ) for( localIndex i = 0; i < 3; ++i ) { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, relTol, absTol ); + testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol, absTol ); } } @@ -694,7 +811,235 @@ TEST_F( DeadOilFluidFromTableTest, numericalDerivativesMolar ) for( localIndex i = 0; i < 3; ++i ) { - testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, relTol ); + testNumericalDerivatives( *fluid, parent, P[i], T, comp, eps, false, relTol ); + } +} + +MultiFluidBase & makeMultiPhaseMultiComponentFluid( string const & name, Group * parent ) +{ + CO2BrineFluid & fluid = parent->registerGroup< CO2BrineFluid >( name ); + + auto & compNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::componentNamesString() ); + compNames.resize( 2 ); + compNames[0] = "co2"; compNames[1] = "water"; + + auto & molarWgt = fluid.getReference< array1d< real64 > >( MultiFluidBase::viewKeyStruct::componentMolarWeightString() ); + molarWgt.resize( 2 ); + molarWgt[0] = 44e-3; molarWgt[1] = 18e-3; + + auto & phaseNames = fluid.getReference< string_array >( MultiFluidBase::viewKeyStruct::phaseNamesString() ); + phaseNames.resize( 2 ); + phaseNames[0] = "gas"; phaseNames[1] = "liquid"; + + auto & phasePVTParaFileNames = fluid.getReference< path_array >( CO2BrineFluid::viewKeyStruct::phasePVTParaFilesString() ); + phasePVTParaFileNames.resize( 2 ); + phasePVTParaFileNames[0] = "pvtgas.txt"; phasePVTParaFileNames[1] = "pvtliquid.txt"; + + auto & flashModelParaFileName = fluid.getReference< Path >( CO2BrineFluid::viewKeyStruct::flashModelParaFileString() ); + flashModelParaFileName = "co2flash.txt"; + + fluid.postProcessInputRecursive(); + return fluid; +} + +class MultiPhaseMultiComponentFluidTest : public CompositionalFluidTestBase +{ +protected: + + MultiPhaseMultiComponentFluidTest() + { + writeTableToFile( "pvtliquid.txt", pvtLiquidTableContent ); + writeTableToFile( "pvtgas.txt", pvtGasTableContent ); + writeTableToFile( "co2flash.txt", co2FlashTableContent ); + + parent.resize( 1 ); + fluid = &makeMultiPhaseMultiComponentFluid( "fluid", &parent ); + + parent.initialize(); + parent.initializePostInitialConditions(); + } + + ~MultiPhaseMultiComponentFluidTest() + { + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); + removeFile( "co2flash.txt" ); + } + +}; + + +TEST_F( MultiPhaseMultiComponentFluidTest, checkAgainstPreviousImplementationMolar ) +{ + fluid->setMassFlag( false ); + + real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; + real64 const T[3] = { 367.65, 368.15, 368.75 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.3; comp[1] = 0.7; + + real64 const relTol = 1e-10; + + fluid->allocateConstitutiveData( fluid->getParent(), 1 ); + + CO2BrineFluid::KernelWrapper wrapper = + dynamicCast< CO2BrineFluid * >( fluid )->createKernelWrapper(); + + real64 const savedTotalDens[] = + { 5881.8128183956969224, 5869.522096458530541, 5854.9469601674582009, 9180.9455320478591602, 9157.2045503913905122, 9129.1751063784995495, 15755.475565136142905, 15696.691553847707837, + 15627.990771463533747 }; + real64 const savedGasPhaseFrac[] = + { 0.29413690046142371148, 0.29415754810481165027, 0.29418169867697463449, 0.29194010802017489326, 0.29196434961986583723, 0.29199266189550621142, 0.2890641335638892695, 0.28908718137828937067, + 0.28911404840933618843 }; + real64 const savedWaterDens[] = + { 53286.457784368176362, 53264.389103437584708, 53237.751306267287873, 53229.257940878436784, 53207.597127679167897, 53181.436584967217641, 53197.49848403003125, 53176.033397316634364, + 53150.105086882285832 }; + real64 const savedGasDens[] = + { 1876.2436091302606656, 1872.184636376355229, 1867.3711104617746059, 3053.1548401973859654, 3044.5748249030266379, 3034.4507978134674886, 5769.0622621289458039, 5742.8476745352018042, + 5712.2837704249559465 }; + real64 const savedWaterMassDens[] = + { 970.85108546544745423, 970.4075834766143771, 969.87385780866463847, 974.23383396044232541, 973.78856424100911227, 973.25280170872576946, 979.48333010951580491, 979.04147229150635212, + 978.50977403260912979 }; + real64 const savedGasMassDens[] = + { 82.554718801731468147, 82.376124000559627802, 82.164328860318079251, 134.33881296868497657, 133.96129229573315911, 133.51583510379256836, 253.83873953367358922, 252.68529767954885301, + 251.34048589869803436 }; + real64 const savedWaterVisc[] = + { 0.00090094759910161340347, 0.00090096652240945261734, 0.00090098923037885969567, 0.00090094759910161340347, 0.00090096652240945261734, 0.00090098923037885969567, 0.00090094759910161340347, + 0.00090096652240945261734, 0.00090098923037885969567 }; + real64 const savedGasVisc[] = + { 1.9042384704865343673e-05, 1.9062615947696152414e-05, 1.9086923154230274463e-05, 2.0061713844617985449e-05, 2.0075955757102255573e-05, 2.0093249989250199265e-05, 2.3889596884008691474e-05, + 2.3865756080512667728e-05, 2.3839170076324036522e-05 }; + real64 const savedWaterPhaseGasComp[] = + { 0.0083062842389820552153, 0.008277274736736653718, 0.0082433415400525456018, 0.011383065290266058955, 0.011349217198060387521, 0.011309682362800700661, 0.015382352969377973903, + 0.015350431636424789056, 0.015313218057419366105 }; + real64 const savedWaterPhaseWaterComp[] = + { 0.99169371576101794652, 0.9917227252632633272, 0.99175665845994742664, 0.98861693470973388553, 0.98865078280193963156, 0.98869031763719927852, 0.98461764703062204518, 0.98464956836357520054, + 0.98468678194258063563 }; + + localIndex counter = 0; + for( localIndex i = 0; i < 3; ++i ) + { + for( localIndex j = 0; j < 3; ++j ) + { + testValuesAgainstPreviousImplementation( wrapper, + P[i], T[j], comp, + savedTotalDens[counter], savedGasPhaseFrac[counter], + savedWaterDens[counter], savedGasDens[counter], + savedWaterMassDens[counter], savedGasMassDens[counter], + savedWaterVisc[counter], savedGasVisc[counter], + savedWaterPhaseGasComp[counter], savedWaterPhaseWaterComp[counter], + relTol ); + counter++; + } + } +} + +TEST_F( MultiPhaseMultiComponentFluidTest, checkAgainstPreviousImplementationMass ) +{ + fluid->setMassFlag( true ); + + real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; + real64 const T[3] = { 367.65, 368.15, 368.75 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.3; comp[1] = 0.7; + + real64 const relTol = 1e-10; + + fluid->allocateConstitutiveData( fluid->getParent(), 1 ); + + CO2BrineFluid::KernelWrapper wrapper = + dynamicCast< CO2BrineFluid * >( fluid )->createKernelWrapper(); + + real64 const savedTotalDens[] = + { 238.33977561940088208, 237.86350488026934613, 237.29874890241927687, 354.01144731214282046, 353.18618684355078585, 352.21120673560858449, 550.02182875764299297, 548.3889751707506548, + 546.47580480217254717 }; + real64 const savedGasPhaseFrac[] = + { 0.28562868803317220667, 0.28567941665326646028, 0.285738749802139258, 0.28022484140718162404, 0.2802844989853667812, 0.28035417162546172332, 0.2731355646393489045, 0.27319238868618361815, + 0.2732586251114847431 }; + real64 const savedWaterDens[] = + { 970.85108546544745423, 970.4075834766143771, 969.87385780866463847, 974.23383396044232541, 973.78856424100911227, 973.25280170872576946, 979.48333010951580491, 979.04147229150635212, + 978.50977403260912979 }; + real64 const savedGasDens[] = + { 82.554718801731468147, 82.376124000559627802, 82.164328860318079251, 134.33881296868497657, 133.96129229573315911, 133.51583510379256836, 253.83873953367358922, 252.68529767954885301, + 251.34048589869803436 }; + real64 const savedWaterMassDens[] = + { 970.85108546544745423, 970.4075834766143771, 969.87385780866463847, 974.23383396044232541, 973.78856424100911227, 973.25280170872576946, 979.48333010951580491, 979.04147229150635212, + 978.50977403260912979 }; + real64 const savedGasMassDens[] = + { 82.554718801731468147, 82.376124000559627802, 82.164328860318079251, 134.33881296868497657, 133.96129229573315911, 133.51583510379256836, 253.83873953367358922, 252.68529767954885301, + 251.34048589869803436 }; + real64 const savedWaterVisc[] = + { 0.00090094759910161340347, 0.00090096652240945261734, 0.00090098923037885969567, 0.00090094759910161340347, 0.00090096652240945261734, 0.00090098923037885969567, 0.00090094759910161340347, + 0.00090096652240945261734, 0.00090098923037885969567 }; + real64 const savedGasVisc[] = + { 1.9042384704865343673e-05, 1.9062615947696152414e-05, 1.9086923154230274463e-05, 2.0061713844617985449e-05, 2.0075955757102255573e-05, 2.0093249989250199265e-05, 2.3889596884008691474e-05, + 2.3865756080512667728e-05, 2.3839170076324036522e-05 }; + real64 const savedWaterPhaseGasComp[] = + { 0.02005966592318779787, 0.019990461277537684842, 0.019909503061226688919, 0.027365230280837819082, 0.027285226317914228894, 0.027191770514265831832, 0.036759501299346700187, + 0.036684965747010883641, 0.036598063202886929601 }; + real64 const savedWaterPhaseWaterComp[] = + { 0.9797478006656266114, 0.97981828292617156873, 0.97990072673671935188, 0.97227194517798976037, 0.97235397979974458327, 0.97244979317916002692, 0.9625743441996873484, 0.9626514061444874093, + 0.962741233539301966 }; + + localIndex counter = 0; + for( localIndex i = 0; i < 3; ++i ) + { + for( localIndex j = 0; j < 3; ++j ) + { + testValuesAgainstPreviousImplementation( wrapper, + P[i], T[j], comp, + savedTotalDens[counter], savedGasPhaseFrac[counter], + savedWaterDens[counter], savedGasDens[counter], + savedWaterMassDens[counter], savedGasMassDens[counter], + savedWaterVisc[counter], savedGasVisc[counter], + savedWaterPhaseGasComp[counter], savedWaterPhaseWaterComp[counter], + relTol ); + counter++; + } + } +} + +TEST_F( MultiPhaseMultiComponentFluidTest, numericalDerivativesMolar ) +{ + fluid->setMassFlag( false ); + + // TODO test over a range of values + real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; + real64 const T[3] = { 367.65, 368.15, 368.75 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.3; comp[1] = 0.7; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 1e-4; + + for( localIndex i = 0; i < 3; ++i ) + { + for( localIndex j = 0; j < 3; ++j ) + { + testNumericalDerivatives( *fluid, parent, P[i], T[j], comp, eps, false, relTol ); + } + } +} + +TEST_F( MultiPhaseMultiComponentFluidTest, numericalDerivativesMass ) +{ + fluid->setMassFlag( true ); + + // TODO test over a range of values + real64 const P[3] = { 5e6, 7.5e6, 1.2e7 }; + real64 const T[3] = { 367.65, 368.15, 368.75 }; + array1d< real64 > comp( 2 ); + comp[0] = 0.3; comp[1] = 0.7; + + real64 const eps = sqrt( std::numeric_limits< real64 >::epsilon()); + real64 const relTol = 1e-8; + + for( localIndex i = 0; i < 3; ++i ) + { + for( localIndex j = 0; j < 3; ++j ) + { + testNumericalDerivatives( *fluid, parent, P[i], T[j], comp, eps, false, relTol ); + } } } diff --git a/src/coreComponents/fileIO/schema/docs/CO2BrineFluid.rst b/src/coreComponents/fileIO/schema/docs/CO2BrineFluid.rst new file mode 100644 index 00000000000..2010eb6efc8 --- /dev/null +++ b/src/coreComponents/fileIO/schema/docs/CO2BrineFluid.rst @@ -0,0 +1,14 @@ + + +==================== ============ ======== ============================================================================== +Name Type Default Description +==================== ============ ======== ============================================================================== +componentMolarWeight real64_array {0} Component molar weights +componentNames string_array {} List of component names +flashModelParaFile path required Name of the file defining the parameters of the flash model +name string required A name is required for any non-unique nodes +phaseNames string_array {} List of fluid phases +phasePVTParaFiles path_array required Names of the files defining the parameters of the viscosity and density models +==================== ============ ======== ============================================================================== + + diff --git a/src/coreComponents/fileIO/schema/docs/MultiPhaseMultiComponentFluid_other.rst b/src/coreComponents/fileIO/schema/docs/CO2BrineFluid_other.rst similarity index 100% rename from src/coreComponents/fileIO/schema/docs/MultiPhaseMultiComponentFluid_other.rst rename to src/coreComponents/fileIO/schema/docs/CO2BrineFluid_other.rst diff --git a/src/coreComponents/fileIO/schema/docs/Constitutive.rst b/src/coreComponents/fileIO/schema/docs/Constitutive.rst index d2c6312e746..a00eea75555 100644 --- a/src/coreComponents/fileIO/schema/docs/Constitutive.rst +++ b/src/coreComponents/fileIO/schema/docs/Constitutive.rst @@ -7,6 +7,7 @@ BlackOilFluid node :ref:`XML_BlackOilFluid` BrooksCoreyBakerRelativePermeability node :ref:`XML_BrooksCoreyBakerRelativePermeability` BrooksCoreyCapillaryPressure node :ref:`XML_BrooksCoreyCapillaryPressure` BrooksCoreyRelativePermeability node :ref:`XML_BrooksCoreyRelativePermeability` +CO2BrineFluid node :ref:`XML_CO2BrineFluid` CompositionalMultiphaseFluid node :ref:`XML_CompositionalMultiphaseFluid` CompressibleSinglePhaseFluid node :ref:`XML_CompressibleSinglePhaseFluid` Contact node :ref:`XML_Contact` @@ -19,7 +20,6 @@ DruckerPrager node :ref:`XML_DruckerPrager` ElasticIsotropic node :ref:`XML_ElasticIsotropic` ElasticTransverseIsotropic node :ref:`XML_ElasticTransverseIsotropic` ExtendedDruckerPrager node :ref:`XML_ExtendedDruckerPrager` -MultiPhaseMultiComponentFluid node :ref:`XML_MultiPhaseMultiComponentFluid` NullModel node :ref:`XML_NullModel` ParticleFluid node :ref:`XML_ParticleFluid` PoreVolumeCompressibleSolid node :ref:`XML_PoreVolumeCompressibleSolid` diff --git a/src/coreComponents/fileIO/schema/docs/Constitutive_other.rst b/src/coreComponents/fileIO/schema/docs/Constitutive_other.rst index 9bc5975aa00..645b1a9a415 100644 --- a/src/coreComponents/fileIO/schema/docs/Constitutive_other.rst +++ b/src/coreComponents/fileIO/schema/docs/Constitutive_other.rst @@ -7,6 +7,7 @@ BlackOilFluid node :ref:`DATASTRUCTURE_BlackOilFluid` BrooksCoreyBakerRelativePermeability node :ref:`DATASTRUCTURE_BrooksCoreyBakerRelativePermeability` BrooksCoreyCapillaryPressure node :ref:`DATASTRUCTURE_BrooksCoreyCapillaryPressure` BrooksCoreyRelativePermeability node :ref:`DATASTRUCTURE_BrooksCoreyRelativePermeability` +CO2BrineFluid node :ref:`DATASTRUCTURE_CO2BrineFluid` CompositionalMultiphaseFluid node :ref:`DATASTRUCTURE_CompositionalMultiphaseFluid` CompressibleSinglePhaseFluid node :ref:`DATASTRUCTURE_CompressibleSinglePhaseFluid` Contact node :ref:`DATASTRUCTURE_Contact` @@ -19,7 +20,6 @@ DruckerPrager node :ref:`DATASTRUCTURE_DruckerPrager` ElasticIsotropic node :ref:`DATASTRUCTURE_ElasticIsotropic` ElasticTransverseIsotropic node :ref:`DATASTRUCTURE_ElasticTransverseIsotropic` ExtendedDruckerPrager node :ref:`DATASTRUCTURE_ExtendedDruckerPrager` -MultiPhaseMultiComponentFluid node :ref:`DATASTRUCTURE_MultiPhaseMultiComponentFluid` NullModel node :ref:`DATASTRUCTURE_NullModel` ParticleFluid node :ref:`DATASTRUCTURE_ParticleFluid` PoreVolumeCompressibleSolid node :ref:`DATASTRUCTURE_PoreVolumeCompressibleSolid` diff --git a/src/coreComponents/fileIO/schema/docs/MultiPhaseMultiComponentFluid.rst b/src/coreComponents/fileIO/schema/docs/MultiPhaseMultiComponentFluid.rst deleted file mode 100644 index 941214d016f..00000000000 --- a/src/coreComponents/fileIO/schema/docs/MultiPhaseMultiComponentFluid.rst +++ /dev/null @@ -1,14 +0,0 @@ - - -==================== ============ ======== ================================================================= -Name Type Default Description -==================== ============ ======== ================================================================= -componentMolarWeight real64_array {0} Component molar weights -componentNames string_array {} List of component names -flashModelParaFile path required name of the filen including flash calculation function parameters -name string required A name is required for any non-unique nodes -phaseNames string_array {} List of fluid phases -phasePVTParaFiles path_array required List of the names of the files including PVT function parameters -==================== ============ ======== ================================================================= - - diff --git a/src/coreComponents/fileIO/schema/schema.xsd b/src/coreComponents/fileIO/schema/schema.xsd index 0a345de88cd..853148e7af4 100644 --- a/src/coreComponents/fileIO/schema/schema.xsd +++ b/src/coreComponents/fileIO/schema/schema.xsd @@ -1656,6 +1656,7 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> + @@ -1668,7 +1669,6 @@ Equal to 1 for surface conditions, and to 0 for reservoir conditions--> - @@ -1742,6 +1742,20 @@ The expected format is "{ waterMax, oilMax }", in that order--> + + + + + + + + + + + + + + @@ -1991,20 +2005,6 @@ For instance, if "oil" is before "gas" in "phaseNames", the table order should b - - - - - - - - - - - - - - diff --git a/src/coreComponents/fileIO/schema/schema.xsd.other b/src/coreComponents/fileIO/schema/schema.xsd.other index 423ea9da26c..b38f029f430 100644 --- a/src/coreComponents/fileIO/schema/schema.xsd.other +++ b/src/coreComponents/fileIO/schema/schema.xsd.other @@ -697,6 +697,7 @@ + @@ -709,7 +710,6 @@ - @@ -811,6 +811,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1061,58 +1113,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index dd1baac7d9a..459a83640de 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp @@ -388,15 +388,16 @@ void CompositionalMultiphaseBase::updateFluidModel( Group & dataGroup, localInde constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { - typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - - // MultiFluid models are not thread-safe or device-capable yet - FluidUpdateKernel::launch< serialPolicy >( dataGroup.size(), - fluidWrapper, - pres, - dPres, - m_temperature, - compFrac ); + using FluidType = TYPEOFREF( castedFluid ); + using ExecPolicy = typename FluidType::exec_policy; + typename FluidType::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); + + FluidUpdateKernel::launch< ExecPolicy >( dataGroup.size(), + fluidWrapper, + pres, + dPres, + m_temperature, + compFrac ); } ); } @@ -973,14 +974,15 @@ void CompositionalMultiphaseBase::applyDirichletBC( real64 const time, constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { - typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - - // MultiFluid models are not thread-safe or device-capable yet - FluidUpdateKernel::launch< serialPolicy >( targetSet, - fluidWrapper, - bcPres, - m_temperature, - compFrac ); + using FluidType = TYPEOFREF( castedFluid ); + using ExecPolicy = typename FluidType::exec_policy; + typename FluidType::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); + + FluidUpdateKernel::launch< ExecPolicy >( targetSet, + fluidWrapper, + bcPres, + m_temperature, + compFrac ); } ); forAll< parallelDevicePolicy<> >( targetSet.size(), [=] GEOSX_HOST_DEVICE ( localIndex const a ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseKernels.hpp index 1b0e8fcab00..c385c83bfa7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBaseKernels.hpp @@ -134,7 +134,7 @@ struct FluidUpdateKernel real64 const temp, arrayView2d< real64 const > const & compFrac ) { - forAll< POLICY >( size, [=] ( localIndex const k ) + forAll< POLICY >( size, [=] GEOSX_HOST_DEVICE ( localIndex const k ) { for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) { @@ -152,7 +152,7 @@ struct FluidUpdateKernel real64 const temp, arrayView2d< real64 const > const & compFrac ) { - forAll< POLICY >( size, [=] ( localIndex const k ) + forAll< POLICY >( size, [=] GEOSX_HOST_DEVICE ( localIndex const k ) { for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) { @@ -170,7 +170,7 @@ struct FluidUpdateKernel real64 const temp, arrayView2d< real64 const > const & compFrac ) { - forAll< POLICY >( targetSet.size(), [=] ( localIndex const a ) + forAll< POLICY >( targetSet.size(), [=] GEOSX_HOST_DEVICE ( localIndex const a ) { localIndex const k = targetSet[a]; for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) @@ -188,7 +188,7 @@ struct FluidUpdateKernel real64 const temp, arrayView2d< real64 const > const & compFrac ) { - forAll< POLICY >( targetSet.size(), [=] ( localIndex const a ) + forAll< POLICY >( targetSet.size(), [=] GEOSX_HOST_DEVICE ( localIndex const a ) { localIndex const k = targetSet[a]; for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/integratedTests/compositionalMultiphaseFlow/co2_flux_3d.xml b/src/coreComponents/physicsSolvers/fluidFlow/integratedTests/compositionalMultiphaseFlow/co2_flux_3d.xml index f22bea933c7..dbc0ac73235 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/integratedTests/compositionalMultiphaseFlow/co2_flux_3d.xml +++ b/src/coreComponents/physicsSolvers/fluidFlow/integratedTests/compositionalMultiphaseFlow/co2_flux_3d.xml @@ -98,7 +98,7 @@ - - ( subRegion.size(), - fluidWrapper, - pres, - dPres, - m_temperature, - compFrac ); + using FluidType = TYPEOFREF( castedFluid ); + using ExecPolicy = typename FluidType::exec_policy; + typename FluidType::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); + + CompositionalMultiphaseBaseKernels::FluidUpdateKernel::launch< ExecPolicy >( subRegion.size(), + fluidWrapper, + pres, + dPres, + m_temperature, + compFrac ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/integratedTests/compositionalMultiphaseWell/staircase_co2_wells_3d.xml b/src/coreComponents/physicsSolvers/fluidFlow/wells/integratedTests/compositionalMultiphaseWell/staircase_co2_wells_3d.xml index 572f50a9970..7c69927fa43 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/integratedTests/compositionalMultiphaseWell/staircase_co2_wells_3d.xml +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/integratedTests/compositionalMultiphaseWell/staircase_co2_wells_3d.xml @@ -45,15 +45,15 @@ control="phaseVolRate" referenceElevation="12" targetBHP="1e6" - targetPhaseRate="1e-7" + targetPhaseRate="1.0e-7" targetPhaseName="water"/> @@ -151,7 +151,7 @@ - @@ -143,7 +143,7 @@ - -