From 3c5801cc86aedc015d9e91465b678e4ad836aff9 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:48:20 -0800 Subject: [PATCH 01/71] Add support for mass constraits (inj wells only) --- .../wells/CompositionalMultiphaseWell.cpp | 9 ++- .../wells/CompositionalMultiphaseWell.hpp | 3 +- .../CompositionalMultiphaseWellKernels.cpp | 55 ++++++++++++++++-- .../CompositionalMultiphaseWellKernels.hpp | 32 +++++++++- .../fluidFlow/wells/WellControls.cpp | 58 ++++++++++++++++++- .../fluidFlow/wells/WellControls.hpp | 31 ++++++++++ 6 files changed, 172 insertions(+), 16 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index ca537b2f6a6..6694603f8c6 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -240,6 +240,7 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) reference().resizeDimension< 0 >( m_numPhases ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() ); + wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentTotalVolRate_dPresString() ). setRestartFlags( RestartFlags::NO_WRITE ); wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ). @@ -687,7 +688,8 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ); real64 & dCurrentTotalVolRate_dRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dRateString() ); - + real64 & massDensity = + wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() ); constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); @@ -721,7 +723,8 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg &iwelemRef, &logLevel, &wellControlsName, - &massUnit] ( localIndex const ) + &massUnit, + &massDensity] ( localIndex const ) { GEOS_UNUSED_VAR( massUnit ); using Deriv = multifluid::DerivativeOffset; @@ -757,7 +760,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg real64 const currentTotalRate = connRate[iwelemRef]; // Step 2.1: compute the inverse of the total density and derivatives - + massDensity =totalDens[iwelemRef][0]; // need to verify this is surface dens real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index da7f355c931..2c7bec2a0a6 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -292,7 +292,8 @@ class CompositionalMultiphaseWell : public WellSolverBase static constexpr char const * allowLocalCompDensChoppingString() { return CompositionalMultiphaseBase::viewKeyStruct::allowLocalCompDensChoppingString(); } // control data (not registered on the mesh) - + + static constexpr char const * massDensityString() { return "massDensity";} static constexpr char const * currentBHPString() { return "currentBHP"; } static constexpr char const * dCurrentBHP_dPresString() { return "dCurrentBHP_dPres"; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index 70a8e51721d..86fdf33ebba 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -40,6 +40,7 @@ ControlEquationHelper:: real64 const & targetBHP, real64 const & targetPhaseRate, real64 const & targetTotalRate, + real64 const & targetMassRate, real64 const & currentBHP, arrayView1d< real64 const > const & currentPhaseVolRate, real64 const & currentTotalVolRate, @@ -102,9 +103,18 @@ ControlEquationHelper:: } else { - newControl = ( currentControl == WellControls::Control::BHP ) - ? WellControls::Control::TOTALVOLRATE - : WellControls::Control::BHP; + if ( targetMassRate == 0.0 ) + { + newControl = ( currentControl == WellControls::Control::BHP ) + ? WellControls::Control::TOTALVOLRATE + : WellControls::Control::BHP; + } + else + { + newControl = ( currentControl == WellControls::Control::BHP ) + ? WellControls::Control::MASSRATE + : WellControls::Control::BHP; + } } } } @@ -120,6 +130,7 @@ ControlEquationHelper:: real64 const & targetBHP, real64 const & targetPhaseRate, real64 const & targetTotalRate, + real64 const & targetMassRate, real64 const & currentBHP, real64 const & dCurrentBHP_dPres, arrayView1d< real64 const > const & dCurrentBHP_dCompDens, @@ -131,6 +142,7 @@ ControlEquationHelper:: real64 const & dCurrentTotalVolRate_dPres, arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, real64 const & dCurrentTotalVolRate_dRate, + real64 const & massDensity, globalIndex const dofNumber, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -179,7 +191,7 @@ ControlEquationHelper:: } } // Total volumetric rate control - else if( currentControl == WellControls::Control::TOTALVOLRATE ) + else if( currentControl == WellControls::Control::TOTALVOLRATE ) { controlEqn = currentTotalVolRate - targetTotalRate; dControlEqn_dPres = dCurrentTotalVolRate_dPres; @@ -188,6 +200,17 @@ ControlEquationHelper:: { dControlEqn_dComp[ic] = dCurrentTotalVolRate_dCompDens[ic]; } + } + // Total mass rate control + else if( currentControl == WellControls::Control::MASSRATE ) + { + controlEqn = massDensity*currentTotalVolRate - targetMassRate; + dControlEqn_dPres = massDensity*dCurrentTotalVolRate_dPres; + dControlEqn_dRate = massDensity*dCurrentTotalVolRate_dRate; + for( integer ic = 0; ic < NC; ++ic ) + { + dControlEqn_dComp[ic] = massDensity*dCurrentTotalVolRate_dCompDens[ic]; + } } else { @@ -610,6 +633,7 @@ PressureRelationKernel:: real64 const targetBHP = wellControls.getTargetBHP( timeAtEndOfStep ); real64 const targetTotalRate = wellControls.getTargetTotalRate( timeAtEndOfStep ); real64 const targetPhaseRate = wellControls.getTargetPhaseRate( timeAtEndOfStep ); + real64 const targetMassRate = wellControls.getTargetMassRate( timeAtEndOfStep ); // dynamic well control data real64 const & currentBHP = @@ -636,6 +660,8 @@ PressureRelationKernel:: wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ); real64 const & dCurrentTotalVolRate_dRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dRateString() ); + real64 const & massDensity = + wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() ); RAJA::ReduceMax< parallelDeviceReduce, localIndex > switchControl( 0 ); @@ -653,6 +679,7 @@ PressureRelationKernel:: targetBHP, targetPhaseRate, targetTotalRate, + targetMassRate, currentBHP, currentPhaseVolRate, currentTotalVolRate, @@ -668,6 +695,7 @@ PressureRelationKernel:: targetBHP, targetPhaseRate, targetTotalRate, + targetMassRate, currentBHP, dCurrentBHP_dPres, dCurrentBHP_dCompDens, @@ -679,6 +707,7 @@ PressureRelationKernel:: dCurrentTotalVolRate_dPres, dCurrentTotalVolRate_dCompDens, dCurrentTotalVolRate_dRate, + massDensity, wellElemDofNumber[iwelemControl], localMatrix, localRhs ); @@ -1746,6 +1775,7 @@ RateInitializationKernel:: bool const isProducer = wellControls.isProducer(); real64 const targetTotalRate = wellControls.getTargetTotalRate( currentTime ); real64 const targetPhaseRate = wellControls.getTargetPhaseRate( currentTime ); + real64 const targetMassRate = wellControls.getTargetMassRate( currentTime ); // Estimate the connection rates forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) @@ -1760,10 +1790,23 @@ RateInitializationKernel:: } else { - connRate[iwelem] = LvArray::math::min( 0.1 * targetTotalRate * totalDens[iwelem][0], 1e3 ); + if ( targetMassRate == 0.0 ) + { + connRate[iwelem] = LvArray::math::min( 0.1 * targetTotalRate * totalDens[iwelem][0], 1e3 ); + } + else + { + connRate[iwelem] = targetMassRate; + } + } } - else + else if( control == WellControls::Control::MASSRATE ) + { + connRate[iwelem] = targetMassRate; + connRate[iwelem] = targetMassRate* totalDens[iwelem][0]; + } + else { if( isProducer ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index ea06e3ae2ad..d76f2976e86 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -92,6 +92,7 @@ struct ControlEquationHelper real64 const & targetBHP, real64 const & targetPhaseRate, real64 const & targetTotalRate, + real64 const & targetMassRate, real64 const & currentBHP, arrayView1d< real64 const > const & currentPhaseVolRate, real64 const & currentTotalVolRate, @@ -107,6 +108,7 @@ struct ControlEquationHelper real64 const & targetBHP, real64 const & targetPhaseRate, real64 const & targetTotalRate, + real64 const & targetMassRate, real64 const & currentBHP, real64 const & dCurrentBHP_dPres, arrayView1d< real64 const > const & dCurrentBHP_dCompDens, @@ -118,6 +120,7 @@ struct ControlEquationHelper real64 const & dCurrentTotalVolRate_dPres, arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, real64 const & dCurrentTotalVolRate_dRate, + real64 const & massDensity, globalIndex const dofNumber, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); @@ -692,6 +695,7 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > m_targetBHP( wellControls.getTargetBHP( timeAtEndOfStep ) ), m_targetTotalRate( wellControls.getTargetTotalRate( timeAtEndOfStep ) ), m_targetPhaseRate( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ), + m_targetMassRate( wellControls.getTargetMassRate( timeAtEndOfStep ) ), m_volume( subRegion.getElementVolume() ), m_phaseDens_n( fluid.phaseDensity_n() ), m_totalDens_n( fluid.totalDensity_n() ) @@ -731,6 +735,11 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > // the residual entry is in volume / time units normalizer = LvArray::math::max( LvArray::math::abs( m_targetPhaseRate ), m_minNormalizer ); } + else if( m_currentControl == WellControls::Control::MASSRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer ); + } } // for the pressure difference equation, always normalize by the BHP else @@ -748,8 +757,16 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > } else // Type::INJECTOR, only TOTALVOLRATE is supported for now { - // the residual is in mass units - normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate ) ; + } + else + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; + } + } // to make sure that everything still works well if the rate is zero, we add this check @@ -765,7 +782,15 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > } else // Type::INJECTOR, only TOTALVOLRATE is supported for now { - normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ); + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate/ m_totalDens_n[iwelem][0] ); + } + else + { + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ); + } + } // to make sure that everything still works well if the rate is zero, we add this check @@ -819,6 +844,7 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > real64 const m_targetBHP; real64 const m_targetTotalRate; real64 const m_targetPhaseRate; + real64 const m_targetMassRate; /// View on the volume arrayView1d< real64 const > const m_volume; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp index 147f7027661..23af7648829 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp @@ -36,6 +36,7 @@ WellControls::WellControls( string const & name, Group * const parent ) m_targetBHP( 0.0 ), m_targetTotalRate( 0.0 ), m_targetPhaseRate( 0.0 ), + m_targetMassRate(0.0), m_useSurfaceConditions( 0 ), m_surfacePres( 0.0 ), m_surfaceTemp( 0.0 ), @@ -79,6 +80,11 @@ WellControls::WellControls( string const & name, Group * const parent ) setInputFlag( InputFlags::OPTIONAL ). setDescription( "Target phase volumetric rate (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s])" ); + registerWrapper( viewKeyStruct::targetMassRateString(), &m_targetMassRate ). + setDefaultValue( 0.0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Target Mass Rate rate ( [kg^3/s])" ); + registerWrapper( viewKeyStruct::targetPhaseNameString(), &m_targetPhaseName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setDefaultValue( "" ). @@ -146,6 +152,11 @@ WellControls::WellControls( string const & name, Group * const parent ) setInputFlag( InputFlags::OPTIONAL ). setDescription( "Name of the phase rate table when the rate is a time dependent function" ); + registerWrapper( viewKeyStruct::targetMassRateTableNameString(), &m_targetMassRateTableName ). + setRTTypeName( rtTypes::CustomTypes::groupNameRef ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Name of the mass rate table when the rate is a time dependent function" ); + registerWrapper( viewKeyStruct::statusTableNameString(), &m_statusTableName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setInputFlag( InputFlags::OPTIONAL ). @@ -175,6 +186,12 @@ void WellControls::switchToPhaseRateControl( real64 const & val ) m_targetPhaseRate = val; } +void WellControls::switchToMassRateControl( real64 const & val ) +{ + m_currentControl = Control::MASSRATE; + m_targetMassRate = val; +} + namespace { @@ -228,6 +245,10 @@ void WellControls::postProcessInput() getWrapperDataContext( viewKeyStruct::targetPhaseRateString() ) << ": Target oil rate is negative", InputError ); + GEOS_THROW_IF( m_targetMassRate < 0, + getWrapperDataContext( viewKeyStruct::targetPhaseRateString() ) << ": Target mass rate is negative", + InputError ); + GEOS_THROW_IF( (m_injectionStream.empty() && m_injectionTemperature >= 0) || (!m_injectionStream.empty() && m_injectionTemperature < 0), "WellControls " << getDataContext() << ": Both " @@ -267,14 +288,18 @@ void WellControls::postProcessInput() // 4) check that at least one rate constraint has been defined GEOS_THROW_IF( ((m_targetPhaseRate <= 0.0 && m_targetPhaseRateTableName.empty()) && + (m_targetMassRate <= 0.0 && m_targetMassRateTableName.empty()) && (m_targetTotalRate <= 0.0 && m_targetTotalRateTableName.empty())), - "WellControls " << getDataContext() << ": You need to specify a phase rate constraint or a total rate constraint. \n" << + "WellControls " << getDataContext() << ": You need to specify a phase, mass, or total rate constraint. \n" << "The phase rate constraint can be specified using " << "either " << viewKeyStruct::targetPhaseRateString() << " or " << viewKeyStruct::targetPhaseRateTableNameString() << ".\n" << "The total rate constraint can be specified using " << "either " << viewKeyStruct::targetTotalRateString() << - " or " << viewKeyStruct::targetTotalRateTableNameString(), + " or " << viewKeyStruct::targetTotalRateTableNameString()<< + "The mass rate constraint can be specified using " << + "either " << viewKeyStruct::targetMassRateString() << + " or " << viewKeyStruct::targetMassRateTableNameString(), InputError ); // 5) check whether redundant information has been provided @@ -293,6 +318,11 @@ void WellControls::postProcessInput() " The keywords " << viewKeyStruct::targetBHPString() << " and " << viewKeyStruct::targetBHPTableNameString() << " cannot be specified together", InputError ); + GEOS_THROW_IF( ((m_targetMassRate > 0.0 && !m_targetMassRateTableName.empty())), + "WellControls " << getDataContext() << ": You have provided redundant information for well mass rate." << + " The keywords " << viewKeyStruct::targetMassRateString() << " and " << viewKeyStruct::targetMassRateTableNameString() << " cannot be specified together", + InputError ); + // 6.1) If the well is under BHP control then the BHP must be specified. // Otherwise the BHP will be set to a default value. if( m_currentControl == Control::BHP ) @@ -317,6 +347,12 @@ void WellControls::postProcessInput() << EnumStrings< Control >::toString( Control::TOTALVOLRATE ), InputError ); + // An injector must be controlled by TotalVolRate + GEOS_THROW_IF( (isProducer() && (m_inputControl == Control::MASSRATE)), + "WellControls " << getDataContext() << ": You have to control an injector with " + << EnumStrings< Control >::toString( Control::MASSRATE ), + InputError ); + // 7) Make sure that the flag disabling crossflow is not used for producers GEOS_THROW_IF( isProducer() && m_isCrossflowEnabled == 0, getWrapperDataContext( viewKeyStruct::enableCrossflowString() ) << @@ -380,7 +416,22 @@ void WellControls::postProcessInput() << m_targetPhaseRateTable->getName() << " should be TableFunction::InterpolationType::Lower", InputError ); } + // Create time-dependent mass rate table + if( m_targetMassRateTableName.empty() ) + { + m_targetMassRateTableName = getName()+"_ConstantMassRate_table"; + m_targetMassRateTable = createWellTable( m_targetMassRateTableName, m_targetMassRate ); + } + else + { + FunctionManager & functionManager = FunctionManager::getInstance(); + m_targetMassRateTable = &(functionManager.getGroup< TableFunction const >( m_targetMassRateTableName )); + GEOS_THROW_IF( m_targetMassRateTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower, + "WellControls " << getDataContext() << ": The interpolation method for the time-dependent mass rate table " + << m_targetMassRateTable->getName() << " should be TableFunction::InterpolationType::Lower", + InputError ); + } // 12) Create the time-dependent well status table if( m_statusTableName.empty()) { @@ -408,7 +459,8 @@ void WellControls::postProcessInput() bool WellControls::isWellOpen( real64 const & currentTime ) const { bool isOpen = true; - if( isZero( getTargetTotalRate( currentTime ) ) && isZero( getTargetPhaseRate( currentTime ) ) ) + if( isZero( getTargetTotalRate( currentTime ) ) && isZero( getTargetPhaseRate( currentTime ) ) + && isZero( getTargetMassRate( currentTime ) )) { isOpen = false; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp index 78f1524e518..4b3a82ae18c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp @@ -61,6 +61,7 @@ class WellControls : public dataRepository::Group BHP, /**< The well operates at a specified bottom hole pressure (BHP) */ PHASEVOLRATE, /**< The well operates at a specified phase volumetric flow rate */ TOTALVOLRATE, /**< The well operates at a specified total volumetric flow rate */ + MASSRATE, /**evaluate( ¤tTime); + } + + /** * @brief Const accessor for the composition of the injection stream * @return a global component fraction vector @@ -276,6 +293,8 @@ class WellControls : public dataRepository::Group static constexpr char const * targetPhaseRateString() { return "targetPhaseRate"; } /// String key for the well target phase name static constexpr char const * targetPhaseNameString() { return "targetPhaseName"; } + /// String key for the well target phase name + static constexpr char const * targetMassRateString() { return "targetMassRate"; } /// String key for the well injection stream static constexpr char const * injectionStreamString() { return "injectionStream"; } /// String key for the well injection temperature @@ -290,6 +309,8 @@ class WellControls : public dataRepository::Group static constexpr char const * targetTotalRateTableNameString() { return "targetTotalRateTableName"; } /// string key for phase rate table name static constexpr char const * targetPhaseRateTableNameString() { return "targetPhaseRateTableName"; } + /// string key for mass rate table name + static constexpr char const * targetMassRateTableNameString() { return "targetMassRateTableName"; } /// string key for BHP table name static constexpr char const * targetBHPTableNameString() { return "targetBHPTableName"; } /// string key for status table name @@ -336,6 +357,9 @@ class WellControls : public dataRepository::Group /// Name of the targeted phase string m_targetPhaseName; + /// Target MassRate + real64 m_targetMassRate; + /// Vector with global component fractions at the injector array1d< real64 > m_injectionStream; @@ -357,6 +381,9 @@ class WellControls : public dataRepository::Group /// Phase rate table name string m_targetPhaseRateTableName; + /// Mass rate table name + string m_targetMassRateTableName; + /// BHP table name string m_targetBHPTableName; @@ -378,6 +405,9 @@ class WellControls : public dataRepository::Group /// Phase rate table TableFunction const * m_targetPhaseRateTable; + /// Mass rate table + TableFunction const * m_targetMassRateTable; + /// BHP table TableFunction const * m_targetBHPTable; @@ -393,6 +423,7 @@ ENUM_STRINGS( WellControls::Control, "BHP", "phaseVolRate", "totalVolRate", + "massRate", "uninitialized" ); From de5b3daa3f1691c6e13ee019850deb8485d69e3e Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 20 Dec 2023 15:31:08 -0800 Subject: [PATCH 02/71] Mass constraint test cases - fixed value & table input --- .../Class09Pb3/class09_pb3_benchmark_mc.xml | 111 ++++++++++++++++++ .../Class09Pb3/class09_pb3_benchmark_mct.xml | 111 ++++++++++++++++++ ...lass09_pb3_drainageOnly_iterative_base.xml | 34 ++++++ 3 files changed, 256 insertions(+) create mode 100644 inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mc.xml create mode 100644 inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mct.xml diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mc.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mc.xml new file mode 100644 index 00000000000..b4edabaad3d --- /dev/null +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mc.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mct.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mct.xml new file mode 100644 index 00000000000..14378119874 --- /dev/null +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_benchmark_mct.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml index 54cffee9212..92890413f4a 100644 --- a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml +++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml @@ -54,6 +54,34 @@ targetTotalRateTableName="totalRateTable" injectionTemperature="353.15" injectionStream="{ 1.0, 0.0 }"/> + + @@ -220,6 +248,12 @@ values="{ 8.02849025 , 0, 0}" interpolation="lower"/> + From 993296d3d92c0e05ed91e48664d41dc32863f9b6 Mon Sep 17 00:00:00 2001 From: tjb Date: Fri, 22 Dec 2023 11:01:30 -0800 Subject: [PATCH 03/71] add proper isZero check --- .../fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index 86fdf33ebba..75a760df6c2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -103,7 +103,7 @@ ControlEquationHelper:: } else { - if ( targetMassRate == 0.0 ) + if ( isZero(targetMassRate) ) { newControl = ( currentControl == WellControls::Control::BHP ) ? WellControls::Control::TOTALVOLRATE @@ -1790,7 +1790,7 @@ RateInitializationKernel:: } else { - if ( targetMassRate == 0.0 ) + if ( isZero(targetMassRate) ) { connRate[iwelem] = LvArray::math::min( 0.1 * targetTotalRate * totalDens[iwelem][0], 1e3 ); } From 825d27d3bf760e7b17b1fc3ab0a4d4b9e1def0f5 Mon Sep 17 00:00:00 2001 From: tjb Date: Wed, 3 Jan 2024 15:28:26 -0800 Subject: [PATCH 04/71] Throw error if massinj constraint and useSurfaceConditions set to 0, fix error message for negative mass rate --- .../physicsSolvers/fluidFlow/wells/WellControls.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp index 23af7648829..16c988048fa 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp @@ -246,7 +246,7 @@ void WellControls::postProcessInput() InputError ); GEOS_THROW_IF( m_targetMassRate < 0, - getWrapperDataContext( viewKeyStruct::targetPhaseRateString() ) << ": Target mass rate is negative", + getWrapperDataContext( viewKeyStruct::targetMassRateString() ) << ": Target mass rate is negative", InputError ); GEOS_THROW_IF( (m_injectionStream.empty() && m_injectionTemperature >= 0) || @@ -323,6 +323,10 @@ void WellControls::postProcessInput() " The keywords " << viewKeyStruct::targetMassRateString() << " and " << viewKeyStruct::targetMassRateTableNameString() << " cannot be specified together", InputError ); + GEOS_THROW_IF( ((m_targetMassRate > 0.0 && m_useSurfaceConditions)), + "WellControls " << getDataContext() << ": Option only valid if useSurfaceConditions set to 1", + InputError ); + // 6.1) If the well is under BHP control then the BHP must be specified. // Otherwise the BHP will be set to a default value. if( m_currentControl == Control::BHP ) From c94eed6fcf08d5045a32230c9cedd628957f8f8f Mon Sep 17 00:00:00 2001 From: tjb Date: Mon, 8 Jan 2024 11:06:29 -0800 Subject: [PATCH 05/71] run make uncrustify_style --- .../wells/CompositionalMultiphaseWell.hpp | 2 +- .../CompositionalMultiphaseWellKernels.cpp | 16 +++++++------- .../CompositionalMultiphaseWellKernels.hpp | 22 +++++++++---------- .../fluidFlow/wells/WellControls.cpp | 8 +++---- .../fluidFlow/wells/WellControls.hpp | 12 +++++----- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 2c7bec2a0a6..54efaf6b60f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -292,7 +292,7 @@ class CompositionalMultiphaseWell : public WellSolverBase static constexpr char const * allowLocalCompDensChoppingString() { return CompositionalMultiphaseBase::viewKeyStruct::allowLocalCompDensChoppingString(); } // control data (not registered on the mesh) - + static constexpr char const * massDensityString() { return "massDensity";} static constexpr char const * currentBHPString() { return "currentBHP"; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index 75a760df6c2..eb6804e71b2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -103,17 +103,17 @@ ControlEquationHelper:: } else { - if ( isZero(targetMassRate) ) + if( isZero( targetMassRate ) ) { newControl = ( currentControl == WellControls::Control::BHP ) ? WellControls::Control::TOTALVOLRATE : WellControls::Control::BHP; - } + } else { newControl = ( currentControl == WellControls::Control::BHP ) ? WellControls::Control::MASSRATE - : WellControls::Control::BHP; + : WellControls::Control::BHP; } } } @@ -191,7 +191,7 @@ ControlEquationHelper:: } } // Total volumetric rate control - else if( currentControl == WellControls::Control::TOTALVOLRATE ) + else if( currentControl == WellControls::Control::TOTALVOLRATE ) { controlEqn = currentTotalVolRate - targetTotalRate; dControlEqn_dPres = dCurrentTotalVolRate_dPres; @@ -201,7 +201,7 @@ ControlEquationHelper:: dControlEqn_dComp[ic] = dCurrentTotalVolRate_dCompDens[ic]; } } - // Total mass rate control + // Total mass rate control else if( currentControl == WellControls::Control::MASSRATE ) { controlEqn = massDensity*currentTotalVolRate - targetMassRate; @@ -1790,7 +1790,7 @@ RateInitializationKernel:: } else { - if ( isZero(targetMassRate) ) + if( isZero( targetMassRate ) ) { connRate[iwelem] = LvArray::math::min( 0.1 * targetTotalRate * totalDens[iwelem][0], 1e3 ); } @@ -1798,7 +1798,7 @@ RateInitializationKernel:: { connRate[iwelem] = targetMassRate; } - + } } else if( control == WellControls::Control::MASSRATE ) @@ -1806,7 +1806,7 @@ RateInitializationKernel:: connRate[iwelem] = targetMassRate; connRate[iwelem] = targetMassRate* totalDens[iwelem][0]; } - else + else { if( isProducer ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index d76f2976e86..b35d807124d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -757,15 +757,15 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > } else // Type::INJECTOR, only TOTALVOLRATE is supported for now { - if( m_currentControl == WellControls::Control::MASSRATE ) - { - normalizer = m_dt * LvArray::math::abs( m_targetMassRate ) ; - } - else - { - // the residual is in mass units - normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; - } + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate ); + } + else + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; + } } @@ -782,7 +782,7 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > } else // Type::INJECTOR, only TOTALVOLRATE is supported for now { - if( m_currentControl == WellControls::Control::MASSRATE ) + if( m_currentControl == WellControls::Control::MASSRATE ) { normalizer = m_dt * LvArray::math::abs( m_targetMassRate/ m_totalDens_n[iwelem][0] ); } @@ -790,7 +790,7 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > { normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ); } - + } // to make sure that everything still works well if the rate is zero, we add this check diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp index 16c988048fa..001767718af 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp @@ -36,7 +36,7 @@ WellControls::WellControls( string const & name, Group * const parent ) m_targetBHP( 0.0 ), m_targetTotalRate( 0.0 ), m_targetPhaseRate( 0.0 ), - m_targetMassRate(0.0), + m_targetMassRate( 0.0 ), m_useSurfaceConditions( 0 ), m_surfacePres( 0.0 ), m_surfaceTemp( 0.0 ), @@ -324,7 +324,7 @@ void WellControls::postProcessInput() InputError ); GEOS_THROW_IF( ((m_targetMassRate > 0.0 && m_useSurfaceConditions)), - "WellControls " << getDataContext() << ": Option only valid if useSurfaceConditions set to 1", + "WellControls " << getDataContext() << ": Option only valid if useSurfaceConditions set to 1", InputError ); // 6.1) If the well is under BHP control then the BHP must be specified. @@ -463,8 +463,8 @@ void WellControls::postProcessInput() bool WellControls::isWellOpen( real64 const & currentTime ) const { bool isOpen = true; - if( isZero( getTargetTotalRate( currentTime ) ) && isZero( getTargetPhaseRate( currentTime ) ) - && isZero( getTargetMassRate( currentTime ) )) + if( isZero( getTargetTotalRate( currentTime ) ) && isZero( getTargetPhaseRate( currentTime ) ) + && isZero( getTargetMassRate( currentTime ) )) { isOpen = false; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp index 4b3a82ae18c..b5a3af4205c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp @@ -198,13 +198,13 @@ class WellControls : public dataRepository::Group */ const string & getTargetPhaseName() const { return m_targetPhaseName; } - /** + /** * @brief Get the target mass rate - * @return the target mass rate + * @return the target mass rate */ - real64 getTargetMassRate(real64 const & currentTime) const - { - return m_rateSign * m_targetMassRateTable->evaluate( ¤tTime); + real64 getTargetMassRate( real64 const & currentTime ) const + { + return m_rateSign * m_targetMassRateTable->evaluate( ¤tTime ); } @@ -293,7 +293,7 @@ class WellControls : public dataRepository::Group static constexpr char const * targetPhaseRateString() { return "targetPhaseRate"; } /// String key for the well target phase name static constexpr char const * targetPhaseNameString() { return "targetPhaseName"; } - /// String key for the well target phase name + /// String key for the well target phase name static constexpr char const * targetMassRateString() { return "targetMassRate"; } /// String key for the well injection stream static constexpr char const * injectionStreamString() { return "injectionStream"; } From 701bce605791ee104d96c32bfea8690ec9738fab Mon Sep 17 00:00:00 2001 From: tjb Date: Mon, 8 Jan 2024 12:29:46 -0800 Subject: [PATCH 06/71] fix for UseSurfaceConditions set to 1 --- .../physicsSolvers/fluidFlow/wells/WellControls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp index 001767718af..4d97682591b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp @@ -323,7 +323,7 @@ void WellControls::postProcessInput() " The keywords " << viewKeyStruct::targetMassRateString() << " and " << viewKeyStruct::targetMassRateTableNameString() << " cannot be specified together", InputError ); - GEOS_THROW_IF( ((m_targetMassRate > 0.0 && m_useSurfaceConditions)), + GEOS_THROW_IF( ((m_targetMassRate > 0.0 && m_useSurfaceConditions==0)), "WellControls " << getDataContext() << ": Option only valid if useSurfaceConditions set to 1", InputError ); From 6858b8166d61aaff2d4af50772951d83514279f1 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Thu, 8 Feb 2024 11:24:07 -0800 Subject: [PATCH 07/71] Thermal well devs --- host-configs/apple/macOS_base.cmake | 29 +- src/coreComponents/dataRepository/Group.hpp | 6 +- .../finiteVolume/FluxApproximationBase.hpp | 1 + .../TwoPointFluxApproximation.cpp | 1 + .../mesh/ElementRegionManager.hpp | 2 + .../fluidFlow/CompositionalMultiphaseBase.cpp | 8 +- ...rmalCompositionalMultiphaseBaseKernels.hpp | 2 + .../wells/CompositionalMultiphaseWell.cpp | 51 ++- .../CompositionalMultiphaseWellFields.hpp | 9 + .../CompositionalMultiphaseWellKernels.hpp | 385 ++++++++++++++++- ...rmalCompositionalMultiphaseWellKernels.hpp | 400 ++++++++++++++++++ .../fluidFlow/wells/WellSolverBase.cpp | 372 ++++++++-------- .../fluidFlow/wells/WellSolverBase.hpp | 9 + 13 files changed, 1076 insertions(+), 199 deletions(-) create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp diff --git a/host-configs/apple/macOS_base.cmake b/host-configs/apple/macOS_base.cmake index 142fbd40d6d..a00bc8e11d6 100644 --- a/host-configs/apple/macOS_base.cmake +++ b/host-configs/apple/macOS_base.cmake @@ -6,12 +6,19 @@ message("CONFIG_NAME = ${CONFIG_NAME}") set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE PATH "") set(CMAKE_CXX_COMPILER "/usr/bin/clang++" CACHE PATH "") +set(CMAKE_FORTRAN_COMPILER "/usr/bin/gfortra`" CACHE PATH "") set(ENABLE_FORTRAN OFF CACHE BOOL "" FORCE) set(ENABLE_MPI ON CACHE PATH "") -set(MPI_C_COMPILER "${HOMEBREW_DIR}/bin/mpicc" CACHE PATH "") -set(MPI_CXX_COMPILER "${HOMEBREW_DIR}/bin/mpicxx" CACHE PATH "") -set(MPIEXEC "${HOMEBREW_DIR}/bin/mpirun" CACHE PATH "") +#set(MPI_C_COMPILER "${HOMEBREW_DIR}/bin/mpicc" CACHE PATH "") +#set(MPI_CXX_COMPILER "${HOMEBREW_DIR}/bin/mpicxx" CACHE PATH "") +#set(MPI_Fortran_COMPILER "${HOMEBREW_DIR}/bin/mpifort" CACHE PATH "") +#set(MPIEXEC "${HOMEBREW_DIR}/bin/mpirun" CACHE PATH "") + +set(MPI_C_COMPILER "mpicc" CACHE PATH "") +set(MPI_CXX_COMPILER "mpicxx" CACHE PATH "") +set(MPI_Fortran_COMPILER "mpifort" CACHE PATH "") +set(MPIEXEC "mpirun" CACHE PATH "") set(ENABLE_GTEST_DEATH_TESTS ON CACHE BOOL "" FORCE) @@ -19,11 +26,18 @@ set(ENABLE_PVTPackage ON CACHE BOOL "" FORCE) set(ENABLE_CUDA "OFF" CACHE PATH "" FORCE) set(ENABLE_OPENMP "OFF" CACHE PATH "" FORCE) - set(ENABLE_CALIPER "OFF" CACHE PATH "" FORCE ) +set(ENABLE_TRILINOS "OFF" CACHE PATH "" FORCE ) +set(ENABLE_PETSC "OFF" CACHE PATH "" FORCE ) +set(ENABLE_SCOTCH "OFF" CACHE PATH "" FORCE ) -set( BLAS_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/libblas.dylib CACHE PATH "" FORCE ) -set( LAPACK_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/liblapack.dylib CACHE PATH "" FORCE ) +#set( BLAS_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/libblas.dylib CACHE PATH "" FORCE ) +#set( LAPACK_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/liblapack.dylib CACHE PATH "" FORCE ) + +#set( BLAS_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/libblas.3.dylib CACHE PATH "" FORCE ) +#set( LAPACK_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/liblapack.3.dylib CACHE PATH "" FORCE ) +set( BLAS_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/libblas.dylib CACHE PATH "" FORCE ) +set( LAPACK_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/liblapack.dylib CACHE PATH "" FORCE ) set(ENABLE_DOXYGEN OFF CACHE BOOL "" FORCE) set(ENABLE_MATHPRESSO OFF CACHE BOOL "" FORCE ) @@ -40,5 +54,6 @@ endif() # ATS set(ATS_ARGUMENTS "--machine openmpi --ats openmpi_mpirun=${MPIEXEC}" CACHE PATH "") - +#set(GEOSX_TPL_DIR "/Users/byer3/GEOS-DEV/thirdPartyLibs/install-mac-debug" CACHE PATH "" FORCE) +set(GEOSX_TPL_DIR "/Users/byer3/GEOS-DEV/thirdPartyLibs/install-mac_rel-release" CACHE PATH "" FORCE) include(${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake) diff --git a/src/coreComponents/dataRepository/Group.hpp b/src/coreComponents/dataRepository/Group.hpp index 6192f3cddab..8a006427082 100644 --- a/src/coreComponents/dataRepository/Group.hpp +++ b/src/coreComponents/dataRepository/Group.hpp @@ -29,6 +29,7 @@ #include +#include #ifndef NOCHARTOSTRING_KEYLOOKUP /// macro definition to enable/disable char * lookups @@ -446,7 +447,7 @@ class Group { using T = std::conditional_t< std::is_const< CONTAINERTYPE >::value, CASTTYPE const, CASTTYPE >; T * const castedContainer = dynamic_cast< T * >( &container ); - + std::cout << " try cast " << typeid(T).name() << std::endl; if( castedContainer != nullptr ) { lambda( *castedContainer ); @@ -587,8 +588,11 @@ class Group void forSubGroups( LOOKUP_CONTAINER const & subGroupKeys, LAMBDA && lambda ) { localIndex counter = 0; + for( auto const & subgroup : subGroupKeys ) { + std::cout << "forSubGroups " << subgroup << std::endl; + applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( getGroup( subgroup ), [&]( auto & castedSubGroup ) { lambda( counter, castedSubGroup ); diff --git a/src/coreComponents/finiteVolume/FluxApproximationBase.hpp b/src/coreComponents/finiteVolume/FluxApproximationBase.hpp index a26320b39c3..ffb974945fa 100644 --- a/src/coreComponents/finiteVolume/FluxApproximationBase.hpp +++ b/src/coreComponents/finiteVolume/FluxApproximationBase.hpp @@ -333,6 +333,7 @@ void FluxApproximationBase::forStencils( MeshLevel const & mesh, LAMBDA && lambd Group const & stencilGroup = mesh.getGroup( groupKeyStruct::stencilMeshGroupString() ).getGroup( getName() ); stencilGroup.forWrappers< TYPE, TYPES... >( [&] ( auto const & wrapper ) { + std::cout << "FluxApproximationBase::forStencils " << wrapper.getName() << std::endl; lambda( wrapper.reference() ); } ); } diff --git a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp index dad365b783c..c9d8b968381 100644 --- a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp +++ b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp @@ -129,6 +129,7 @@ void TwoPointFluxApproximation::computeCellStencil( MeshLevel & mesh ) const localIndex const ei, CellElementRegion const & ) { + std::cout << "computeCellStencil " << ei << std::endl; regionFilter.insert( ei ); } ); diff --git a/src/coreComponents/mesh/ElementRegionManager.hpp b/src/coreComponents/mesh/ElementRegionManager.hpp index 9a75cbc164b..a372b2df2fa 100644 --- a/src/coreComponents/mesh/ElementRegionManager.hpp +++ b/src/coreComponents/mesh/ElementRegionManager.hpp @@ -557,6 +557,8 @@ class ElementRegionManager : public ObjectManagerBase template< typename SUBREGIONTYPE, typename ... SUBREGIONTYPES, typename LOOKUP_CONTAINER, typename LAMBDA > void forElementSubRegions( LOOKUP_CONTAINER const & targetRegions, LAMBDA && lambda ) { + for (auto jj : targetRegions) + std::cout << "forElementSubRegions " << jj << std::endl; forElementSubRegionsComplete< SUBREGIONTYPE, SUBREGIONTYPES... >( targetRegions, [lambda = std::forward< LAMBDA >( lambda )]( localIndex const targetIndex, localIndex const, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index c2edc85b3c8..00bb36f056d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp @@ -242,6 +242,7 @@ void CompositionalMultiphaseBase::registerDataOnMesh( Group & meshBodies ) MultiFluidBase const & referenceFluid = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName ); m_numPhases = referenceFluid.numFluidPhases(); m_numComponents = referenceFluid.numFluidComponents(); + m_isThermal = referenceFluid.isThermal(); } // n_c components + one pressure ( + one temperature if needed ) @@ -1320,10 +1321,13 @@ void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( Dom MeshLevel const & mesh, arrayView1d< string const > const & regionNames ) { + std::cout << "assembleAccumulationAndVolumeBalanceTerms : domain " << domain.getName() << std::endl; mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const, ElementSubRegionBase const & subRegion ) { + std::cout << "assembleAccumulationAndVolumeBalanceTerms : subregion " << subRegion.getName() << std::endl; + string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); string const & solidName = subRegion.getReference< string >( viewKeyStruct::solidNamesString() ); @@ -2146,9 +2150,9 @@ void CompositionalMultiphaseBase::computeCFLNumbers( geos::DomainPartition & dom fluxApprox.forAllStencils( mesh, [&] ( auto & stencil ) { - typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); - + std::cout << "fluxApprox.forAllStencils : mesh " << mesh.getName() << std::endl; + // While this kernel is waiting for a factory class, pass all the accessors here isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1 < isothermalCompositionalMultiphaseFVMKernels::CFLFluxKernel >( numComps, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp index 2afbf350956..1d8956a66f8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp @@ -767,11 +767,13 @@ class ElementBasedAssemblyKernel } // check zero diagonal (works only in debug) + /* for( integer ic = 0; ic < numComp; ++ic ) { GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); } + */ } template< typename FUNC = NoOpFunc > diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 6694603f8c6..ea2d249bb40 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -38,6 +38,7 @@ #include "physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" @@ -145,9 +146,10 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) MultiFluidBase const & fluid0 = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName ); m_numPhases = fluid0.numFluidPhases(); m_numComponents = fluid0.numFluidComponents(); + m_isThermal = fluid0.isThermal(); } - m_numDofPerWellElement = m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate - m_numDofPerResElement = m_numComponents + 1; // 1 pressure + NC compositions + m_numDofPerWellElement = m_isThermal ? m_numComponents + 3 : m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate + temp if thermal + m_numDofPerResElement = m_isThermal ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure + NC compositions + temp if thermal // loop over the wells forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, @@ -198,6 +200,10 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< fields::well::dTotalMassDensity_dPressure >( getName() ); subRegion.registerField< fields::well::dTotalMassDensity_dGlobalCompDensity >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); + if ( fluid.isThermal() ) + { + subRegion.registerField< fields::well::dTotalMassDensity_dTemperature >( getName() ); + } subRegion.registerField< fields::well::phaseVolumeFraction_n >( getName() ). reference().resizeDimension< 1 >( m_numPhases ); @@ -863,12 +869,23 @@ void CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegio string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - isothermalCompositionalMultiphaseBaseKernels:: - PhaseVolumeFractionKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_numComponents, - m_numPhases, - subRegion, - fluid ); + + real64 maxDeltaPhaseVolFrac = + m_isThermal ? + thermalCompositionalMultiphaseBaseKernels:: + PhaseVolumeFractionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + subRegion, + fluid ) +: isothermalCompositionalMultiphaseBaseKernels:: + PhaseVolumeFractionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + subRegion, + fluid ); + + maxDeltaPhaseVolFrac = MpiWrapper::max( maxDeltaPhaseVolFrac ); } @@ -878,12 +895,20 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - + fluid.isThermal() ? + thermalCompositionalMultiphaseWellKernels:: + TotalMassDensityKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + subRegion, + fluid ) + : TotalMassDensityKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, subRegion, fluid ); + } void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) @@ -893,12 +918,12 @@ void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & s // update volumetric rates for the well constraints // note: this must be called before updateFluidModel - updateVolRatesForConstraint( subRegion ); + updateVolRatesForConstraint( subRegion ); // tjb - thermal +++ looks like it does a lot more... // update densities, phase fractions, phase volume fractions - updateFluidModel( subRegion ); - updatePhaseVolumeFraction( subRegion ); - updateTotalMassDensity( subRegion ); + updateFluidModel( subRegion ); // Calculate fluid properties + updatePhaseVolumeFraction( subRegion ); // tjb - thermal + updateTotalMassDensity( subRegion ); // tjb - thermal // update the current BHP pressure updateBHPForConstraint( subRegion ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp index 4caa44d670b..b35189b496c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp @@ -129,6 +129,15 @@ DECLARE_FIELD( dTotalMassDensity_dPressure, NO_WRITE, "Derivative of total mass density with respect to pressure" ); +DECLARE_FIELD( dTotalMassDensity_dTemperature, + "dTotalMassDensity_dTemperature", + array1d< real64 >, + 0, + NOPLOT, + NO_WRITE, + "Derivative of total mass density with respect to temperature" ); + + DECLARE_FIELD( dTotalMassDensity_dGlobalCompDensity, "dTotalMassDensity_dComp", // to avoid a rebaseline array2dLayoutFluid_dC, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index b35d807124d..64d7ebdb297 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -580,7 +580,7 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne + phaseVolFrac[ip] * dMassDens_dC[ic]; } - totalMassDensityKernelOp( ip, totalMassDens, dTotalMassDens_dPres, dTotalMassDens_dCompDens ); + totalMassDensityKernelOp( ip ); //, phaseVolFrac, dTotalMassDens_dPres, dTotalMassDens_dCompDens ); } } @@ -998,6 +998,389 @@ class SolutionCheckKernelFactory }; +/******************************** ElementBasedAssemblyKernel ********************************/ + +/** + * @class ElementBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance + */ +template< integer NUM_COMP, integer NUM_DOF > +class ElementBasedAssemblyKernel +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations + static constexpr integer numEqn = NUM_DOF; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel( localIndex const numPhases, + globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) + : m_numPhases( numPhases ), + m_rankOffset( rankOffset ), + m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), + m_elemGhostRank( subRegion.ghostRank() ), + m_volume( subRegion.getElementVolume() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseVolFrac_n( subRegion.getField< fields::flow::phaseVolumeFraction_n >() ), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_phaseDens_n( fluid.phaseDensity_n() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ), + m_phaseCompFrac_n( fluid.phaseCompFraction_n() ), + m_phaseCompFrac( fluid.phaseCompFraction() ), + m_dPhaseCompFrac( fluid.dPhaseCompFraction() ), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_compDens_n( subRegion.getField< fields::flow::globalCompDensity_n >() ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ), + m_kernelFlags( kernelFlags ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + // volume information (used by both accumulation and volume balance) + real64 volume = 0.0; + + // Residual information + + /// Index of the local row corresponding to this element + localIndex localRow = -1; + + /// Indices of the matrix rows/columns corresponding to the dofs in this element + globalIndex dofIndices[numDof]{}; + + /// C-array storage for the element local residual vector (all equations except volume balance) + real64 localResidual[numEqn]{}; + + /// C-array storage for the element local Jacobian matrix (all equations except volume balance, all dofs) + real64 localJacobian[numEqn][numDof]{}; + + }; + + /** + * @brief Getter for the ghost rank of an element + * @param[in] ei the element index + * @return the ghost rank of the element + */ + GEOS_HOST_DEVICE + integer elemGhostRank( localIndex const ei ) const + { return m_elemGhostRank( ei ); } + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + // initialize the volume + stack.volume = m_volume[ei]; + + // set row index and degrees of freedom indices for this element + stack.localRow = m_dofNumber[ei] - m_rankOffset; + for( integer idof = 0; idof < numDof; ++idof ) + { + stack.dofIndices[idof] = m_dofNumber[ei] + idof; + } + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseAmountKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack, + FUNC && phaseAmountKernelOp = NoOpFunc{} ) const + { + + using Deriv = multifluid::DerivativeOffset; + + // construct the slices for variables accessed multiple times + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac_n = m_phaseVolFrac_n[ei]; + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens_n = m_phaseDens_n[ei][0]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; + + arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac_n = m_phaseCompFrac_n[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; + arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; + + // temporary work arrays + real64 dPhaseAmount_dC[numComp]{}; + real64 dPhaseCompFrac_dC[numComp]{}; + + // sum contributions to component accumulation from each phase + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + real64 const phaseAmount = stack.volume * phaseVolFrac[ip] * phaseDens[ip]; + real64 const phaseAmount_n = stack.volume * phaseVolFrac_n[ip] * phaseDens_n[ip]; + + real64 const dPhaseAmount_dP = stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); + + // assemble density dependence + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] + + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; + dPhaseAmount_dC[jc] *= stack.volume; + } + + // ic - index of component whose conservation equation is assembled + // (i.e. row number in local matrix) + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const phaseCompAmount = phaseAmount * phaseCompFrac[ip][ic]; + real64 const phaseCompAmount_n = phaseAmount_n * phaseCompFrac_n[ip][ic]; + + real64 const dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dP]; + + stack.localResidual[ic] += phaseCompAmount - phaseCompAmount_n; + stack.localJacobian[ic][0] += dPhaseCompAmount_dP; + + // jc - index of component w.r.t. whose compositional var the derivative is being taken + // (i.e. col number in local matrix) + + // assemble phase composition dependence + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dPhaseCompFrac_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmount + + phaseCompFrac[ip][ic] * dPhaseAmount_dC[jc]; + + stack.localJacobian[ic][jc + 1] += dPhaseCompAmount_dC; + } + } + + // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives + // possible use: assemble the derivatives wrt temperature, and the accumulation term of the energy equation for this phase + phaseAmountKernelOp( ip, phaseAmount, phaseAmount_n, dPhaseAmount_dP, dPhaseAmount_dC ); + + } + + // check zero diagonal (works only in debug) + /* + for( integer ic = 0; ic < numComp; ++ic ) + { + GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, + GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); + } + */ + } + + + /** + * @brief Compute the local volume balance contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseVolFractionSumKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeVolumeBalance( localIndex const ei, + StackVariables & stack, + FUNC && phaseVolFractionSumKernelOp = NoOpFunc{} ) const + { + using Deriv = multifluid::DerivativeOffset; + + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + real64 oneMinusPhaseVolFracSum = 1.0; + + // sum contributions to component accumulation from each phase + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + oneMinusPhaseVolFracSum -= phaseVolFrac[ip]; + stack.localJacobian[numComp][0] -= dPhaseVolFrac[ip][Deriv::dP]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localJacobian[numComp][jc+1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; + } + } + + // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives + // possible use: assemble the derivatives wrt temperature, and use oneMinusPhaseVolFracSum if poreVolume depends on temperature + // tjb revisit + phaseVolFractionSumKernelOp( oneMinusPhaseVolFracSum ); + + // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) + stack.localResidual[numComp] = stack.volume * oneMinusPhaseVolFracSum; + for( integer idof = 0; idof < numDof; ++idof ) + { + stack.localJacobian[numComp][idof] *= stack.volume; + } + + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const GEOS_UNUSED_PARAM( ei ), + StackVariables & stack ) const + { + using namespace compositionalMultiphaseUtilities; + + if( m_kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) + { + // apply equation/variable change transformation to the component mass balance equations + real64 work[numDof]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localResidual ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // - the volume balance equations (i = numComp) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + integer const numRows = numComp+1; + for( integer i = 0; i < numRows; ++i ) + { + m_localRhs[stack.localRow + i] += stack.localResidual[i]; + m_localMatrix.addToRow< serialAtomic >( stack.localRow + i, + stack.dofIndices, + stack.localJacobian[i], + numDof ); + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.elemGhostRank( ei ) >= 0 ) + { + return; + } + + typename KERNEL_TYPE::StackVariables stack; + + kernelComponent.setup( ei, stack ); + kernelComponent.computeAccumulation( ei, stack ); + kernelComponent.computeVolumeBalance( ei, stack ); + kernelComponent.complete( ei, stack ); + } ); + } + +protected: + + /// Number of fluid phases + integer const m_numPhases; + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_dofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_elemGhostRank; + + /// View on the element volumes + arrayView1d< real64 const > const m_volume; + + /// Views on the porosity + arrayView2d< real64 const > const m_porosity_n; + arrayView2d< real64 const > const m_porosity; + arrayView2d< real64 const > const m_dPoro_dPres; + + /// Views on the derivatives of comp fractions wrt component density + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dCompFrac_dCompDens; + + /// Views on the phase volume fractions + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac_n; + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > const m_dPhaseVolFrac; + + /// Views on the phase densities + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens_n; + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseDens; + + /// Views on the phase component fraction + arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const m_phaseCompFrac_n; + arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const m_phaseCompFrac; + arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const m_dPhaseCompFrac; + + // Views on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + arrayView2d< real64 const, compflow::USD_COMP > m_compDens_n; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const m_kernelFlags; +}; + +/** + * @class ElementBasedAssemblyKernelFactory + */ + } // end namespace compositionalMultiphaseWellKernels diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp new file mode 100644 index 00000000000..46edd0405e3 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -0,0 +1,400 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalCompositionalMultiphaseWellKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP + +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" + +namespace geos +{ + + namespace thermalCompositionalMultiphaseWellKernels + { + + using namespace constitutive; + + /******************************** TotalMassDensityKernel ****************************/ + + /** + * @class TotalMassDensityKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Define the interface for the property kernel in charge of computing the total mass density + */ + template + class TotalMassDensityKernel : public compositionalMultiphaseWellKernels::TotalMassDensityKernel + { + public: + using Base = compositionalMultiphaseWellKernels::TotalMassDensityKernel; + using Base::m_dCompFrac_dCompDens; + using Base::m_dPhaseMassDens; + using Base::m_dPhaseVolFrac; + using Base::m_dTotalMassDens_dCompDens; + using Base::m_dTotalMassDens_dPres; + using Base::m_phaseMassDens; + using Base::m_phaseVolFrac; + using Base::m_totalMassDens; + using Base::numComp; + using Base::numPhase; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + TotalMassDensityKernel(ObjectManagerBase &subRegion, + MultiFluidBase const &fluid) + : Base(subRegion, fluid), + m_dTotalMassDens_dTemp(subRegion.getField()) + { + } + + /** + * @brief Compute the total mass density in an element + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[in] totalMassDensityKernelOp the function used to customize the kernel + */ + template + GEOS_HOST_DEVICE inline void compute(localIndex const ei, + FUNC &&totalMassDensityKernelOp = NoOpFunc{}) const + { + using Deriv = multifluid::DerivativeOffset; + + arraySlice1d phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice1d phaseMassDens = m_phaseMassDens[ei][0]; + arraySlice2d dPhaseMassDens = m_dPhaseMassDens[ei][0]; + real64 &totalMassDens = m_totalMassDens[ei]; + real64 &dTotalMassDens_dTemp = m_dTotalMassDens_dTemp[ei]; + + // Call the base compute the compute the total mass density and derivatives + return Base::compute(ei, [&](localIndex const ip) + { dTotalMassDens_dTemp += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; }); + } + + protected: + // outputs + arrayView1d m_dTotalMassDens_dTemp; + }; + + /** + * @class TotalMassDensityKernelFactory + */ + class TotalMassDensityKernelFactory + { + public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template + static void + createAndLaunch(integer const numComp, + integer const numPhase, + ObjectManagerBase &subRegion, + MultiFluidBase const &fluid) + { + if (numPhase == 2) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch(numComp, [&](auto NC) + { + integer constexpr NUM_COMP = NC(); + TotalMassDensityKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); + TotalMassDensityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); }); + } + else if (numPhase == 3) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch(numComp, [&](auto NC) + { + integer constexpr NUM_COMP = NC(); + TotalMassDensityKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + TotalMassDensityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); }); + } + } + }; + + /******************************** ElementBasedAssemblyKernel ********************************/ + + /** + * @class ElementBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of thermal accumulation and volume balance + */ + template + class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel + { + public: + using Base = compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel; + using Base::m_dCompFrac_dCompDens; + using Base::m_dofNumber; + using Base::m_dPhaseCompFrac; + using Base::m_dPhaseDens; + using Base::m_dPhaseVolFrac; + using Base::m_dPoro_dPres; + using Base::m_elemGhostRank; + using Base::m_localMatrix; + using Base::m_localRhs; + using Base::m_numPhases; + using Base::m_phaseCompFrac; + using Base::m_phaseCompFrac_n; + using Base::m_phaseDens; + using Base::m_phaseDens_n; + using Base::m_phaseVolFrac; + using Base::m_phaseVolFrac_n; + using Base::m_porosity; + using Base::m_porosity_n; + using Base::m_rankOffset; + using Base::m_volume; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel(localIndex const numPhases, + globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const &subRegion, + MultiFluidBase const &fluid, + CRSMatrixView const &localMatrix, + arrayView1d const &localRhs, + BitFlags const kernelFlags) + : Base(numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags), + m_phaseInternalEnergy_n(fluid.phaseInternalEnergy_n()), + m_phaseInternalEnergy(fluid.phaseInternalEnergy()), + m_dPhaseInternalEnergy(fluid.dPhaseInternalEnergy()) + { + } + + struct StackVariables : public Base::StackVariables + { + public: + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + { + } + + using Base::StackVariables::dofIndices; + using Base::StackVariables::localJacobian; + using Base::StackVariables::localResidual; + using Base::StackVariables::localRow; + using Base::StackVariables::volume; + + + + }; + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup(localIndex const ei, + StackVariables &stack) const + { + Base::setup(ei, stack); + + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeAccumulation(localIndex const ei, + StackVariables &stack) const + { + using Deriv = multifluid::DerivativeOffset; + + Base::computeAccumulation(ei, stack, [&](integer const ip, real64 const &phaseAmount, real64 const &phaseAmount_n, real64 const &dPhaseAmount_dP, real64 const(&dPhaseAmount_dC)[numComp]) + { + // We are in the loop over phases, ip provides the current phase index. + // We have to do two things: + // 1- Assemble the derivatives of the component mass balance equations with respect to temperature + // 2- Assemble the phase-dependent part of the accumulation term of the energy equation + + real64 dPhaseInternalEnergy_dC[numComp]{}; + + // construct the slices + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; + arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy_n = m_phaseInternalEnergy_n[ei][0]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseInternalEnergy = m_dPhaseInternalEnergy[ei][0]; + + // Step 1: assemble the derivatives of the component mass balance equations with respect to temperature + + real64 const dPhaseAmount_dT = stack.volume * (dPhaseVolFrac[ip][Deriv::dT] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dT] ); + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localJacobian[ic][numDof-1] += dPhaseAmount_dT * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dT]; + } + + // Step 2: assemble the phase-dependent part of the accumulation term of the energy equation + + real64 const phaseEnergy = phaseAmount * phaseInternalEnergy[ip]; + real64 const phaseEnergy_n = phaseAmount_n * phaseInternalEnergy_n[ip]; + real64 const dPhaseEnergy_dP = dPhaseAmount_dP * phaseInternalEnergy[ip] + + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP]; + real64 const dPhaseEnergy_dT = dPhaseAmount_dT * phaseInternalEnergy[ip] + + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dT]; + + // local accumulation + stack.localResidual[numEqn-1] += phaseEnergy - phaseEnergy_n; + + // derivatives w.r.t. pressure and temperature + stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP; + stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; + + // derivatives w.r.t. component densities + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount_dC[jc] + + dPhaseInternalEnergy_dC[jc] * phaseAmount; + } }); + + + } + + /** + * @brief Compute the local volume balance contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeVolumeBalance(localIndex const ei, + StackVariables &stack) const + { + using Deriv = multifluid::DerivativeOffset; + + Base::computeVolumeBalance(ei, stack, [&](real64 const &oneMinusPhaseVolFraction) + { + GEOS_UNUSED_VAR( oneMinusPhaseVolFraction ); + + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + stack.localJacobian[numEqn-2][numDof-1] -= dPhaseVolFrac[ip][Deriv::dT]; + } }); + } + + GEOS_HOST_DEVICE + void complete(localIndex const ei, + StackVariables &stack) const + { + // Step 1: assemble the component mass balance equations and volume balance equations + Base::complete(ei, stack); + + // Step 2: assemble the energy equation + m_localRhs[stack.localRow + numEqn - 1] += stack.localResidual[numEqn - 1]; + m_localMatrix.template addToRow(stack.localRow + numEqn - 1, + stack.dofIndices, + stack.localJacobian[numEqn - 1], + numDof); + } + + protected: + /// View on derivative of porosity w.r.t temperature + arrayView2d const m_dPoro_dTemp; + + /// Views on phase internal energy + arrayView3d m_phaseInternalEnergy_n; + arrayView3d m_phaseInternalEnergy; + arrayView4d m_dPhaseInternalEnergy; + + }; + + /** + * @class ElementBasedAssemblyKernelFactory + */ + class ElementBasedAssemblyKernelFactory + { + public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template + static void + createAndLaunch(localIndex const numComps, + localIndex const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + ElementSubRegionBase const &subRegion, + MultiFluidBase const &fluid, + CRSMatrixView const &localMatrix, + arrayView1d const &localRhs) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch(numComps, [&](auto NC) + { + localIndex constexpr NUM_COMP = NC(); + localIndex constexpr NUM_DOF = NC()+2; + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + + ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > + kernel( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); + ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); }); + } + }; + + }; // end namespace thermalCompositionalMultiphaseWellKernels + +} // end namespace geos + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 0699870a3df..4014a22581b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -26,73 +26,72 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp" #include "fileIO/Outputs/OutputBase.hpp" namespace geos { -using namespace dataRepository; -using namespace constitutive; + using namespace dataRepository; + using namespace constitutive; -WellSolverBase::WellSolverBase( string const & name, - Group * const parent ) - : SolverBase( name, parent ), - m_numDofPerWellElement( 0 ), - m_numDofPerResElement( 0 ), - m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" ) ) -{ - this->getWrapper< string >( viewKeyStruct::discretizationString() ). - setInputFlag( InputFlags::FALSE ); -} - -Group * WellSolverBase::createChild( string const & childKey, string const & childName ) -{ - Group * rval = nullptr; - - if( childKey == keys::wellControls ) + WellSolverBase::WellSolverBase(string const &name, + Group *const parent) + : SolverBase(name, parent), + m_numDofPerWellElement(0), + m_numDofPerResElement(0), + m_isThermal(false), + m_ratesOutputDir(joinPath(OutputBase::getOutputDirectory(), name + "_rates")) { - rval = ®isterGroup< WellControls >( childName ); + this->getWrapper(viewKeyStruct::discretizationString()).setInputFlag(InputFlags::FALSE); } - else - { - SolverBase::createChild( childKey, childName ); - } - return rval; -} -void WellSolverBase::expandObjectCatalogs() -{ - createChild( keys::wellControls, keys::wellControls ); -} + Group *WellSolverBase::createChild(string const &childKey, string const &childName) + { + Group *rval = nullptr; + if (childKey == keys::wellControls) + { + rval = ®isterGroup(childName); + } + else + { + SolverBase::createChild(childKey, childName); + } + return rval; + } -WellSolverBase::~WellSolverBase() = default; + void WellSolverBase::expandObjectCatalogs() + { + createChild(keys::wellControls, keys::wellControls); + } -void WellSolverBase::postProcessInput() -{ - SolverBase::postProcessInput(); + WellSolverBase::~WellSolverBase() = default; - // create dir for rates output - if( getLogLevel() > 0 ) + void WellSolverBase::postProcessInput() { - if( MpiWrapper::commRank() == 0 ) + SolverBase::postProcessInput(); + + // create dir for rates output + if (getLogLevel() > 0) { - makeDirsForPath( m_ratesOutputDir ); + if (MpiWrapper::commRank() == 0) + { + makeDirsForPath(m_ratesOutputDir); + } + // wait till the dir is created by rank 0 + MPI_Barrier(MPI_COMM_WORLD); } - // wait till the dir is created by rank 0 - MPI_Barrier( MPI_COMM_WORLD ); } -} - -void WellSolverBase::registerDataOnMesh( Group & meshBodies ) -{ - SolverBase::registerDataOnMesh( meshBodies ); - - forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & meshLevel, - arrayView1d< string const > const & regionNames ) + void WellSolverBase::registerDataOnMesh(Group &meshBodies) { + SolverBase::registerDataOnMesh(meshBodies); + + forDiscretizationOnMeshTargets(meshBodies, [&](string const &, + MeshLevel &meshLevel, + arrayView1d const ®ionNames) + { ElementRegionManager & elementRegionManager = meshLevel.getElemManager(); elementRegionManager.forElementSubRegions< WellElementSubRegion >( regionNames, @@ -109,27 +108,23 @@ void WellSolverBase::registerDataOnMesh( Group & meshBodies ) PerforationData * const perforationData = subRegion.getPerforationData(); perforationData->registerField< fields::well::gravityCoefficient >( getName() ); - } ); - } ); -} + } ); }); + } -void WellSolverBase::setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const -{ - SolverBase::setConstitutiveNamesCallSuper( subRegion ); - subRegion.registerWrapper< string >( viewKeyStruct::fluidNamesString() ). - setPlotLevel( PlotLevel::NOPLOT ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ); -} - -void WellSolverBase::setupDofs( DomainPartition const & domain, - DofManager & dofManager ) const -{ - map< std::pair< string, string >, array1d< string > > meshTargets; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const & meshBodyName, - MeshLevel const & meshLevel, - arrayView1d< string const > const & regionNames ) + void WellSolverBase::setConstitutiveNamesCallSuper(ElementSubRegionBase &subRegion) const { + SolverBase::setConstitutiveNamesCallSuper(subRegion); + subRegion.registerWrapper(viewKeyStruct::fluidNamesString()).setPlotLevel(PlotLevel::NOPLOT).setRestartFlags(RestartFlags::NO_WRITE).setSizedFromParent(0); + } + + void WellSolverBase::setupDofs(DomainPartition const &domain, + DofManager &dofManager) const + { + map, array1d> meshTargets; + forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &meshBodyName, + MeshLevel const &meshLevel, + arrayView1d const ®ionNames) + { array1d< string > regions; ElementRegionManager const & elementRegionManager = meshLevel.getElemManager(); elementRegionManager.forElementRegions< WellElementRegion >( regionNames, @@ -139,136 +134,163 @@ void WellSolverBase::setupDofs( DomainPartition const & domain, regions.emplace_back( region.getName() ); } ); auto const key = std::make_pair( meshBodyName, meshLevel.getName()); - meshTargets[key] = std::move( regions ); - } ); - - dofManager.addField( wellElementDofName(), - FieldLocation::Elem, - numDofPerWellElement(), - meshTargets ); - - dofManager.addCoupling( wellElementDofName(), - wellElementDofName(), - DofManager::Connector::Node ); -} - -void WellSolverBase::implicitStepSetup( real64 const & time_n, - real64 const & GEOS_UNUSED_PARAM( dt ), - DomainPartition & domain ) -{ - // Initialize the primary and secondary variables for the first time step - if( time_n <= 0.0 ) - { - initializeWells( domain ); - } -} - -void WellSolverBase::assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); + meshTargets[key] = std::move( regions ); }); - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + dofManager.addField(wellElementDofName(), + FieldLocation::Elem, + numDofPerWellElement(), + meshTargets); - // then assemble the volume balance equations - assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + dofManager.addCoupling(wellElementDofName(), + wellElementDofName(), + DofManager::Connector::Node); + } - // then assemble the pressure relations between well elements - assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); + void WellSolverBase::implicitStepSetup(real64 const &time_n, + real64 const &GEOS_UNUSED_PARAM(dt), + DomainPartition &domain) + { + // Initialize the primary and secondary variables for the first time step + if (time_n <= 0.0) + { + initializeWells(domain); + } + } - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( domain ); + void WellSolverBase::assembleSystem(real64 const time, + real64 const dt, + DomainPartition &domain, + DofManager const &dofManager, + CRSMatrixView const &localMatrix, + arrayView1d const &localRhs) + { + GEOS_MARK_FUNCTION; + if (m_isThermal) + { + integer const useTotalMassEquation = 1; + string const wellDofKey = dofManager.getKey(wellElementDofName()); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + ElementRegionManager const &elemManager = mesh.getElemManager(); + string const dofKey = dofManager.getKey(CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString()); + string const &fluidName = subRegion.getReference(viewKeyStruct::fluidNamesString()); + + MultiFluidBase const &fluid = getConstitutiveModel(subRegion, fluidName); + int numComponents = fluid.numFluidPhases(); + int numPhases = fluid.numFluidComponents(); + + thermalCompositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch>(numComponents, + numPhases, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs); + }); + }); + } + else + { + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms(domain, dofManager, localMatrix, localRhs); - // then apply a special treatment to the wells that are shut - shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); -} + // then assemble the flux terms in the mass balance equations + assembleFluxTerms(dt, domain, dofManager, localMatrix, localRhs); -void WellSolverBase::updateState( DomainPartition & domain ) -{ + // then assemble the volume balance equations + assembleVolumeBalanceTerms(domain, dofManager, localMatrix, localRhs); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - updateSubRegionState( subRegion ); - } ); - } ); -} + // then assemble the pressure relations between well elements + assemblePressureRelations(time, dt, domain, dofManager, localMatrix, localRhs); -void WellSolverBase::initializePostInitialConditionsPreSubGroups() -{ - SolverBase::initializePostInitialConditionsPreSubGroups(); + // then compute the perforation rates (later assembled by the coupled solver) + computePerforationRates(domain); + } - DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); + // then apply a special treatment to the wells that are shut + shutDownWell(time, dt, domain, dofManager, localMatrix, localRhs); + } - // make sure that nextWellElementIndex is up-to-date (will be used in well initialization and assembly) - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + void WellSolverBase::updateState(DomainPartition &domain) { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - subRegion.reconstructLocalConnectivity(); - } ); - } ); - // Precompute solver-specific constant data (e.g. gravity-coefficient) - precomputeData( domain ); -} + forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &, + MeshLevel &mesh, + arrayView1d const ®ionNames) + { mesh.getElemManager().forElementSubRegions(regionNames, [&](localIndex const, + WellElementSubRegion &subRegion) + { updateSubRegionState(subRegion); }); }); + } -void WellSolverBase::precomputeData( DomainPartition & domain ) -{ - R1Tensor const gravVector = gravityVector(); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + void WellSolverBase::initializePostInitialConditionsPreSubGroups() { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - PerforationData & perforationData = *subRegion.getPerforationData(); - WellControls & wellControls = getWellControls( subRegion ); - real64 const refElev = wellControls.getReferenceElevation(); + SolverBase::initializePostInitialConditionsPreSubGroups(); - arrayView2d< real64 const > const wellElemLocation = subRegion.getElementCenter(); - arrayView1d< real64 > const wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); + DomainPartition &domain = this->getGroupByPath("/Problem/domain"); - arrayView2d< real64 const > const perfLocation = perforationData.getField< fields::perforation::location >(); - arrayView1d< real64 > const perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >(); + // make sure that nextWellElementIndex is up-to-date (will be used in well initialization and assembly) + forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &, + MeshLevel &mesh, + arrayView1d const ®ionNames) + { mesh.getElemManager().forElementSubRegions(regionNames, [&](localIndex const, + WellElementSubRegion &subRegion) + { subRegion.reconstructLocalConnectivity(); }); }); - forAll< serialPolicy >( perforationData.size(), [=]( localIndex const iperf ) - { + // Precompute solver-specific constant data (e.g. gravity-coefficient) + precomputeData(domain); + } + + void WellSolverBase::precomputeData(DomainPartition &domain) + { + R1Tensor const gravVector = gravityVector(); + forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &, + MeshLevel &mesh, + arrayView1d const ®ionNames) + { mesh.getElemManager().forElementSubRegions(regionNames, [&](localIndex const, + WellElementSubRegion &subRegion) + { + PerforationData &perforationData = *subRegion.getPerforationData(); + WellControls &wellControls = getWellControls(subRegion); + real64 const refElev = wellControls.getReferenceElevation(); + + arrayView2d const wellElemLocation = subRegion.getElementCenter(); + arrayView1d const wellElemGravCoef = subRegion.getField(); + + arrayView2d const perfLocation = perforationData.getField(); + arrayView1d const perfGravCoef = perforationData.getField(); + + forAll(perforationData.size(), [=](localIndex const iperf) + { // precompute the depth of the perforations - perfGravCoef[iperf] = LvArray::tensorOps::AiBi< 3 >( perfLocation[iperf], gravVector ); - } ); + perfGravCoef[iperf] = LvArray::tensorOps::AiBi< 3 >( perfLocation[iperf], gravVector ); }); - forAll< serialPolicy >( subRegion.size(), [=]( localIndex const iwelem ) - { + forAll(subRegion.size(), [=](localIndex const iwelem) + { // precompute the depth of the well elements - wellElemGravCoef[iwelem] = LvArray::tensorOps::AiBi< 3 >( wellElemLocation[iwelem], gravVector ); - } ); - - // set the reference well element where the BHP control is applied - wellControls.setReferenceGravityCoef( refElev * gravVector[ 2 ] ); + wellElemGravCoef[iwelem] = LvArray::tensorOps::AiBi< 3 >( wellElemLocation[iwelem], gravVector ); }); - } ); - } ); -} + // set the reference well element where the BHP control is applied + wellControls.setReferenceGravityCoef(refElev * gravVector[2]); }); }); + } -WellControls & WellSolverBase::getWellControls( WellElementSubRegion const & subRegion ) -{ return this->getGroup< WellControls >( subRegion.getWellControlsName() ); } + WellControls &WellSolverBase::getWellControls(WellElementSubRegion const &subRegion) + { + return this->getGroup(subRegion.getWellControlsName()); + } -WellControls const & WellSolverBase::getWellControls( WellElementSubRegion const & subRegion ) const -{ return this->getGroup< WellControls >( subRegion.getWellControlsName() ); } + WellControls const &WellSolverBase::getWellControls(WellElementSubRegion const &subRegion) const + { + return this->getGroup(subRegion.getWellControlsName()); + } } // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index f07890a1363..91eb5d138bf 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -97,6 +97,12 @@ class WellSolverBase : public SolverBase */ localIndex numDofPerResElement() const { return m_numDofPerResElement; } + /** + * @brief getter for iso/thermal switch + * @return True if thermal + */ + localIndex isThermal() const { return m_isThermal; } + /** * @brief get the name of DOF defined on well elements * @return name of the DOF field used by derived solver type @@ -311,6 +317,9 @@ class WellSolverBase : public SolverBase /// the number of Degrees of Freedom per reservoir element integer m_numDofPerResElement; + /// flag indicating whether thermal formulation is used + integer m_isThermal; + string const m_ratesOutputDir; }; From 8fd8f409ef586cb0b55484d48ceb32d3f8f3d4b4 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 13 Feb 2024 15:11:31 -0800 Subject: [PATCH 08/71] Fix rel mode compiler errors ++ --- src/coreComponents/dataRepository/Group.hpp | 4 -- .../wells/CompositionalMultiphaseWell.cpp | 64 +++++++++++++++++-- .../wells/CompositionalMultiphaseWell.hpp | 6 +- .../CompositionalMultiphaseWellFields.hpp | 41 ++++++++++-- .../CompositionalMultiphaseWellKernels.cpp | 38 ++++++++++- .../CompositionalMultiphaseWellKernels.hpp | 10 +++ ...rmalCompositionalMultiphaseWellKernels.hpp | 6 +- .../fluidFlow/wells/WellSolverBase.cpp | 3 +- 8 files changed, 151 insertions(+), 21 deletions(-) diff --git a/src/coreComponents/dataRepository/Group.hpp b/src/coreComponents/dataRepository/Group.hpp index 8a006427082..6090e17952c 100644 --- a/src/coreComponents/dataRepository/Group.hpp +++ b/src/coreComponents/dataRepository/Group.hpp @@ -447,7 +447,6 @@ class Group { using T = std::conditional_t< std::is_const< CONTAINERTYPE >::value, CASTTYPE const, CASTTYPE >; T * const castedContainer = dynamic_cast< T * >( &container ); - std::cout << " try cast " << typeid(T).name() << std::endl; if( castedContainer != nullptr ) { lambda( *castedContainer ); @@ -591,8 +590,6 @@ class Group for( auto const & subgroup : subGroupKeys ) { - std::cout << "forSubGroups " << subgroup << std::endl; - applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( getGroup( subgroup ), [&]( auto & castedSubGroup ) { lambda( counter, castedSubGroup ); @@ -874,7 +871,6 @@ class Group for( auto const & subGroupIter : m_subGroups ) { - std::cout << indent << subGroupIter.second->getName() << std::endl; subGroupIter.second->generateDataStructureSkeleton( level + 1 ); } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index ea2d249bb40..a6fe21ab132 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -197,6 +197,9 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) reference().resizeDimension< 1, 2 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC subRegion.registerField< fields::well::totalMassDensity >( getName() ); + subRegion.registerField< fields::well::dTotalMassDensity >( getName() ). + reference().resizeDimension< 1 >( m_numComponents +2 ); // dP, dT, dC + // tjb - remove subRegion.registerField< fields::well::dTotalMassDensity_dPressure >( getName() ); subRegion.registerField< fields::well::dTotalMassDensity_dGlobalCompDensity >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); @@ -215,6 +218,9 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) PerforationData & perforationData = *subRegion.getPerforationData(); perforationData.registerField< fields::well::compPerforationRate >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); + perforationData.registerField< fields::well::dCompPerforationRate >( getName() ). + reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); + // tjb - remove perforationData.registerField< fields::well::dCompPerforationRate_dPres >( getName() ). reference().resizeDimension< 1, 2 >( 2, m_numComponents ); perforationData.registerField< fields::well::dCompPerforationRate_dComp >( getName() ). @@ -222,8 +228,15 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) WellControls & wellControls = getWellControls( subRegion ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() ); + + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). + setSizedFromParent( 0 ). + reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC + + //tjb - remove wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentBHP_dPresString() ). setRestartFlags( RestartFlags::NO_WRITE ); + //tjb - remove wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHP_dCompDensString() ). setRestartFlags( RestartFlags::NO_WRITE ). setSizedFromParent( 0 ). @@ -232,10 +245,17 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::currentPhaseVolRateString() ). setSizedFromParent( 0 ). reference().resizeDimension< 0 >( m_numPhases ); + + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ). + setSizedFromParent( 0 ). + reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC + + //tjb -remove wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dPresString() ). setRestartFlags( RestartFlags::NO_WRITE ). setSizedFromParent( 0 ). reference().resizeDimension< 0 >( m_numPhases ); + //tjb remove wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ). setRestartFlags( RestartFlags::NO_WRITE ). setSizedFromParent( 0 ). @@ -245,8 +265,13 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) setSizedFromParent( 0 ). reference().resizeDimension< 0 >( m_numPhases ); - wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() ); + + wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() ); + wellControls.registerWrapper >( viewKeyStruct::dCurrentTotalVolRateString() ). + setSizedFromParent( 0 ). + reference().resizeDimension< 0 >( m_numComponents + 3 ); // dP, dT, dC dQ + wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentTotalVolRate_dPresString() ). setRestartFlags( RestartFlags::NO_WRITE ); wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ). @@ -579,6 +604,8 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); arrayView1d< real64 > const & totalMassDens = subRegion.getField< fields::well::totalMassDensity >(); + arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDenss = subRegion.getField< fields::well::dTotalMassDensity >(); + arrayView1d< real64 > const & dTotalMassDens_dPres = subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens_dCompDens = subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); @@ -593,6 +620,9 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & real64 & currentBHP = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ); + arrayView1d< real64 > const & dCurrentBHP = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); + real64 & dCurrentBHP_dPres = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); arrayView1d< real64 > const & dCurrentBHP_dCompDens = @@ -602,15 +632,19 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & forAll< serialPolicy >( 1, [&numComp, pres, totalMassDens, + dTotalMassDenss, dTotalMassDens_dPres, dTotalMassDens_dCompDens, wellElemGravCoef, ¤tBHP, + &dCurrentBHP, &dCurrentBHP_dPres, dCurrentBHP_dCompDens, &iwelemRef, &refGravCoef] ( localIndex const ) { + GEOS_UNUSED_VAR( dTotalMassDenss ); + GEOS_UNUSED_VAR( dCurrentBHP ); real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef; dCurrentBHP_dPres = 1 + dTotalMassDens_dPres[iwelemRef] * diffGravCoef; @@ -679,15 +713,20 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg arrayView1d< real64 > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); + arrayView1d< real64 > const & dCurrentPhaseVolRate = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); + // tjb - remove arrayView1d< real64 > const & dCurrentPhaseVolRate_dPres = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); - arrayView2d< real64 > const & dCurrentPhaseVolRate_dCompDens = - wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ); arrayView1d< real64 > const & dCurrentPhaseVolRate_dRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dRateString() ); - + arrayView2d< real64 > const & dCurrentPhaseVolRate_dCompDens = + wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ); real64 & currentTotalVolRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); + arrayView1d< real64 > const & dCurrentTotalVolRate = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); + // TJB - remove real64 & dCurrentTotalVolRate_dPres = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); arrayView1d< real64 > const & dCurrentTotalVolRate_dCompDens = @@ -719,10 +758,12 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg &surfacePres, &surfaceTemp, ¤tTotalVolRate, + dCurrentTotalVolRate, &dCurrentTotalVolRate_dPres, dCurrentTotalVolRate_dCompDens, &dCurrentTotalVolRate_dRate, currentPhaseVolRate, + dCurrentPhaseVolRate, dCurrentPhaseVolRate_dPres, dCurrentPhaseVolRate_dCompDens, dCurrentPhaseVolRate_dRate, @@ -733,6 +774,8 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg &massDensity] ( localIndex const ) { GEOS_UNUSED_VAR( massUnit ); + GEOS_UNUSED_VAR( dCurrentPhaseVolRate ); + GEOS_UNUSED_VAR( dCurrentTotalVolRate ); using Deriv = multifluid::DerivativeOffset; stackArray1d< real64, maxNumComp > work( numComp ); @@ -1411,6 +1454,9 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom arrayView1d< real64 const > const & wellElemTotalMassDens = subRegion.getField< fields::well::totalMassDensity >(); + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens = + subRegion.getField< fields::well::dTotalMassDensity >(); + //tjb - remove arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres = subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = @@ -1430,7 +1476,10 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom perforationData->getField< fields::perforation::wellTransmissibility >(); arrayView2d< real64 > const & compPerfRate = - perforationData->getField< fields::well::compPerforationRate >(); + perforationData->getField< fields::well::compPerforationRate >(); + arrayView4d< real64 > const & dCompPerfRate = + perforationData->getField< fields::well::dCompPerforationRate >(); + // tjb - remove arrayView3d< real64 > const & dCompPerfRate_dPres = perforationData->getField< fields::well::dCompPerforationRate_dPres >(); arrayView4d< real64 > const & dCompPerfRate_dComp = @@ -1465,6 +1514,7 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom wellElemPres, wellElemCompDens, wellElemTotalMassDens, + dWellElemTotalMassDens, dWellElemTotalMassDens_dPres, dWellElemTotalMassDens_dCompDens, wellElemCompFrac, @@ -1476,6 +1526,7 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom resElementSubRegion, resElementIndex, compPerfRate, + dCompPerfRate, dCompPerfRate_dPres, dCompPerfRate_dComp ); @@ -1655,6 +1706,8 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time // get total mass density on well elements (for potential calculations) arrayView1d< real64 const > const & wellElemTotalMassDens = subRegion.getField< fields::well::totalMassDensity >(); + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens = + subRegion.getField< fields::well::dTotalMassDensity >(); arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres = subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = @@ -1676,6 +1729,7 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time nextWellElemIndex, wellElemPres, wellElemTotalMassDens, + dWellElemTotalMassDens, dWellElemTotalMassDens_dPres, dWellElemTotalMassDens_dCompDens, controlHasSwitched, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 54efaf6b60f..85c40951350 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -294,13 +294,16 @@ class CompositionalMultiphaseWell : public WellSolverBase // control data (not registered on the mesh) static constexpr char const * massDensityString() { return "massDensity";} + static constexpr char const * currentBHPString() { return "currentBHP"; } + static constexpr char const * dCurrentBHPString() { return "dCurrentBHP"; } static constexpr char const * dCurrentBHP_dPresString() { return "dCurrentBHP_dPres"; } - static constexpr char const * dCurrentBHP_dCompDensString() { return "dCurrentBHP_dCompDens"; } static constexpr char const * currentPhaseVolRateString() { return "currentPhaseVolumetricRate"; } + static constexpr char const * dCurrentPhaseVolRateString() { return "dCurrentPhaseVolumetricRate"; } + static constexpr char const * dCurrentPhaseVolRate_dPresString() { return "dCurrentPhaseVolumetricRate_dPres"; } @@ -309,6 +312,7 @@ class CompositionalMultiphaseWell : public WellSolverBase static constexpr char const * dCurrentPhaseVolRate_dRateString() { return "dCurrentPhaseVolumetricRate_dRate"; } static constexpr char const * currentTotalVolRateString() { return "currentTotalVolumetricRate"; } + static constexpr char const * dCurrentTotalVolRateString() { return "dCurrentTotalVolumetricRate"; } static constexpr char const * dCurrentTotalVolRate_dPresString() { return "dCurrentTotalVolumetricRate_dPres"; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp index b35189b496c..5b7481ae80c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp @@ -1,4 +1,4 @@ -/* + /* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * @@ -112,7 +112,23 @@ DECLARE_FIELD( phaseVolumeFraction_n, NOPLOT, WRITE_AND_READ, "Phase volume fraction at the previous converged time step" ); +/* +DECLARE_FIELD( dCurrentBHP, + "dCurrentBHP", + array1d< real64 >, + 0, + NOPLOT, + NO_WRITE, + "Derivative of current BHP with respect to pressure, temperature, and global component density" ); +DECLARE_FIELD( dCurrentPhaseVolRate, + "dCurrentPhaseVolRate", + array2dLayoutPhase, + 0, + NOPLOT, + NO_WRITE, + "Derivative of current phase volume rate with respect to pressure, temperature, and global component density" ); +*/ DECLARE_FIELD( totalMassDensity, "totalMassDensity", array1d< real64 >, @@ -121,14 +137,23 @@ DECLARE_FIELD( totalMassDensity, WRITE_AND_READ, "Total mass density" ); -DECLARE_FIELD( dTotalMassDensity_dPressure, +DECLARE_FIELD( dTotalMassDensity, + "dTotalMassDensity", + array2dLayoutFluid_dC, + 0, + NOPLOT, + NO_WRITE, + "Derivative of total mass density with respect to pressure, temperature, and global component density" ); + +//tjb - remove +DECLARE_FIELD( dTotalMassDensity_dPressure, "dTotalMassDensity_dPressure", array1d< real64 >, 0, NOPLOT, NO_WRITE, "Derivative of total mass density with respect to pressure" ); - +//tjb - remove DECLARE_FIELD( dTotalMassDensity_dTemperature, "dTotalMassDensity_dTemperature", array1d< real64 >, @@ -137,7 +162,7 @@ DECLARE_FIELD( dTotalMassDensity_dTemperature, NO_WRITE, "Derivative of total mass density with respect to temperature" ); - +//tjb - remove DECLARE_FIELD( dTotalMassDensity_dGlobalCompDensity, "dTotalMassDensity_dComp", // to avoid a rebaseline array2dLayoutFluid_dC, @@ -154,6 +179,14 @@ DECLARE_FIELD( compPerforationRate, WRITE_AND_READ, "Component perforation rate" ); +DECLARE_FIELD( dCompPerforationRate, + "dCompPerforationRate", + array4d< real64 >, + 0, + NOPLOT, + NO_WRITE, + "Derivative of component perforation rate with respect to pressure temperature and global component density" ); + DECLARE_FIELD( dCompPerforationRate_dPres, "dCompPerforationRate_dPres", array3d< real64 >, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index eb6804e71b2..a48b751dae8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -132,13 +132,16 @@ ControlEquationHelper:: real64 const & targetTotalRate, real64 const & targetMassRate, real64 const & currentBHP, + arrayView1d< real64 const > const & dCurrentBHP, real64 const & dCurrentBHP_dPres, arrayView1d< real64 const > const & dCurrentBHP_dCompDens, arrayView1d< real64 const > const & currentPhaseVolRate, + arrayView1d< real64 const > const & dCurrentPhaseVolRate, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, real64 const & currentTotalVolRate, + arrayView1d< real64 const > const & dCurrentTotalVolRate, real64 const & dCurrentTotalVolRate_dPres, arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, real64 const & dCurrentTotalVolRate_dRate, @@ -147,6 +150,10 @@ ControlEquationHelper:: CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { + + GEOS_UNUSED_VAR(dCurrentBHP); + GEOS_UNUSED_VAR(dCurrentPhaseVolRate); + GEOS_UNUSED_VAR(dCurrentTotalVolRate); localIndex const eqnRowIndex = dofNumber + ROFFSET::CONTROL - rankOffset; globalIndex const presDofColIndex = dofNumber + COFFSET::DPRES; globalIndex const rateDofColIndex = dofNumber + COFFSET::DCOMP + NC; @@ -568,6 +575,8 @@ PressureRelationKernel:: real64 const & presNext, real64 const & totalMassDens, real64 const & totalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, real64 const & dTotalMassDens_dPres, real64 const & dTotalMassDens_dPresNext, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, @@ -575,6 +584,8 @@ PressureRelationKernel:: real64 & localPresRel, real64 ( & localPresRelJacobian )[2*(NC+1)] ) { + GEOS_UNUSED_VAR(dTotalMassDens); + GEOS_UNUSED_VAR(dTotalMassDensNext); // local working variables and arrays real64 dAvgMassDens_dCompCurrent[NC]{}; real64 dAvgMassDens_dCompNext[NC]{}; @@ -620,6 +631,7 @@ PressureRelationKernel:: arrayView1d< localIndex const > const & nextWellElemIndex, arrayView1d< real64 const > const & wellElemPressure, arrayView1d< real64 const > const & wellElemTotalMassDens, + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, bool & controlHasSwitched, @@ -638,6 +650,9 @@ PressureRelationKernel:: // dynamic well control data real64 const & currentBHP = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ); + arrayView1d< real64 const > const & dCurrentBHP = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); + // tjb - remove real64 const & dCurrentBHP_dPres = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); arrayView1d< real64 const > const & dCurrentBHP_dCompDens = @@ -645,6 +660,9 @@ PressureRelationKernel:: arrayView1d< real64 const > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); + arrayView1d< real64 const > const & dCurrentPhaseVolRate = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); + // tjb - remove arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens = @@ -654,6 +672,9 @@ PressureRelationKernel:: real64 const & currentTotalVolRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); + arrayView1d< real64 const > const & dCurrentTotalVolRate = + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); + // tjb - remove real64 const & dCurrentTotalVolRate_dPres = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens = @@ -697,13 +718,16 @@ PressureRelationKernel:: targetTotalRate, targetMassRate, currentBHP, + dCurrentBHP, dCurrentBHP_dPres, dCurrentBHP_dCompDens, currentPhaseVolRate, + dCurrentPhaseVolRate, dCurrentPhaseVolRate_dPres, dCurrentPhaseVolRate_dCompDens, dCurrentPhaseVolRate_dRate, currentTotalVolRate, + dCurrentTotalVolRate, dCurrentTotalVolRate_dPres, dCurrentTotalVolRate_dCompDens, dCurrentTotalVolRate_dRate, @@ -727,6 +751,8 @@ PressureRelationKernel:: wellElemPressure[iwelemNext], wellElemTotalMassDens[iwelem], wellElemTotalMassDens[iwelemNext], + dWellElemTotalMassDens[iwelem], + dWellElemTotalMassDens[iwelemNext], dWellElemTotalMassDens_dPres[iwelem], dWellElemTotalMassDens_dPres[iwelemNext], dWellElemTotalMassDens_dCompDens[iwelem], @@ -776,6 +802,7 @@ PressureRelationKernel:: arrayView1d< localIndex const > const & nextWellElemIndex, \ arrayView1d< real64 const > const & wellElemPressure, \ arrayView1d< real64 const > const & wellElemTotalMassDens, \ + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, \ arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, \ arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, \ bool & controlHasSwitched, \ @@ -812,6 +839,7 @@ PerforationKernel:: real64 const & wellElemPres, arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompDens, real64 const & wellElemTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens, real64 const & dWellElemTotalMassDens_dPres, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens_dCompDens, arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompFrac, @@ -819,11 +847,13 @@ PerforationKernel:: real64 const & perfGravCoef, real64 const & trans, arraySlice1d< real64 > const & compPerfRate, + arraySlice3d< real64 > const & dCompPerfRate, arraySlice2d< real64 > const & dCompPerfRate_dPres, arraySlice3d< real64 > const & dCompPerfRate_dComp ) { using Deriv = multifluid::DerivativeOffset; - + GEOS_UNUSED_VAR(dWellElemTotalMassDens); + GEOS_UNUSED_VAR(dCompPerfRate); // local working variables and arrays real64 pres[2]{}; real64 dPres_dP[2]{}; @@ -1127,6 +1157,7 @@ PerforationKernel:: arrayView1d< real64 const > const & wellElemPres, arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, arrayView1d< real64 const > const & wellElemTotalMassDens, + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, @@ -1138,6 +1169,7 @@ PerforationKernel:: arrayView1d< localIndex const > const & resElementSubRegion, arrayView1d< localIndex const > const & resElementIndex, arrayView2d< real64 > const & compPerfRate, + arrayView4d< real64 > const & dCompPerfRate, arrayView3d< real64 > const & dCompPerfRate_dPres, arrayView4d< real64 > const & dCompPerfRate_dComp ) { @@ -1171,6 +1203,7 @@ PerforationKernel:: wellElemPres[iwelem], wellElemCompDens[iwelem], wellElemTotalMassDens[iwelem], + dWellElemTotalMassDens[iwelem], dWellElemTotalMassDens_dPres[iwelem], dWellElemTotalMassDens_dCompDens[iwelem], wellElemCompFrac[iwelem], @@ -1178,6 +1211,7 @@ PerforationKernel:: perfGravCoef[iperf], perfTrans[iperf], compPerfRate[iperf], + dCompPerfRate[iperf], dCompPerfRate_dPres[iperf], dCompPerfRate_dComp[iperf] ); @@ -1205,6 +1239,7 @@ PerforationKernel:: arrayView1d< real64 const > const & wellElemPres, \ arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, \ arrayView1d< real64 const > const & wellElemTotalMassDens, \ + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, \ arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, \ arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, \ arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, \ @@ -1216,6 +1251,7 @@ PerforationKernel:: arrayView1d< localIndex const > const & resElementSubRegion, \ arrayView1d< localIndex const > const & resElementIndex, \ arrayView2d< real64 > const & compPerfRate, \ + arrayView4d< real64 > const & dCompPerfRate, \ arrayView3d< real64 > const & dCompPerfRate_dPres, \ arrayView4d< real64 > const & dCompPerfRate_dComp ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 64d7ebdb297..cf7a4990e2c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -110,13 +110,16 @@ struct ControlEquationHelper real64 const & targetTotalRate, real64 const & targetMassRate, real64 const & currentBHP, + arrayView1d< real64 const > const & dCurrentBHP, real64 const & dCurrentBHP_dPres, arrayView1d< real64 const > const & dCurrentBHP_dCompDens, arrayView1d< real64 const > const & currentPhaseVolRate, + arrayView1d< real64 const > const & dCurrentPhaseVolRate, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, real64 const & currentTotalVolRate, + arrayView1d< real64 const > const & dCurrentTotalVolRate, real64 const & dCurrentTotalVolRate_dPres, arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, real64 const & dCurrentTotalVolRate_dRate, @@ -198,6 +201,8 @@ struct PressureRelationKernel real64 const & presNext, real64 const & totalMassDens, real64 const & totalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, real64 const & dTotalMassDens_dPres, real64 const & dTotalMassDens_dPresNext, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, @@ -219,6 +224,7 @@ struct PressureRelationKernel arrayView1d< localIndex const > const & nextWellElemIndex, arrayView1d< real64 const > const & wellElemPressure, arrayView1d< real64 const > const & wellElemTotalMassDens, + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, bool & controlHasSwitched, @@ -287,6 +293,7 @@ struct PerforationKernel real64 const & wellElemPres, arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompDens, real64 const & wellElemTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens, real64 const & dWellElemTotalMassDens_dPres, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens_dCompDens, arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompFrac, @@ -294,6 +301,7 @@ struct PerforationKernel real64 const & perfGravCoef, real64 const & trans, arraySlice1d< real64 > const & compPerfRate, + arraySlice3d< real64 > const & dCompPerfRate, arraySlice2d< real64 > const & dCompPerfRate_dPres, arraySlice3d< real64 > const & dCompPerfRate_dComp ); @@ -317,6 +325,7 @@ struct PerforationKernel arrayView1d< real64 const > const & wellElemPres, arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, arrayView1d< real64 const > const & wellElemTotalMassDens, + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, @@ -328,6 +337,7 @@ struct PerforationKernel arrayView1d< localIndex const > const & resElementSubRegion, arrayView1d< localIndex const > const & resElementIndex, arrayView2d< real64 > const & compPerfRate, + arrayView4d< real64 > const & dCompPerfRate, arrayView3d< real64 > const & dCompPerfRate_dPres, arrayView4d< real64 > const & dCompPerfRate_dComp ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 46edd0405e3..818530789d1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -71,9 +71,7 @@ namespace geos * @param[in] ei the element index * @param[in] totalMassDensityKernelOp the function used to customize the kernel */ - template - GEOS_HOST_DEVICE inline void compute(localIndex const ei, - FUNC &&totalMassDensityKernelOp = NoOpFunc{}) const + GEOS_HOST_DEVICE inline void compute(localIndex const ei) const { using Deriv = multifluid::DerivativeOffset; @@ -81,7 +79,7 @@ namespace geos arraySlice2d dPhaseVolFrac = m_dPhaseVolFrac[ei]; arraySlice1d phaseMassDens = m_phaseMassDens[ei][0]; arraySlice2d dPhaseMassDens = m_dPhaseMassDens[ei][0]; - real64 &totalMassDens = m_totalMassDens[ei]; + real64 &dTotalMassDens_dTemp = m_dTotalMassDens_dTemp[ei]; // Call the base compute the compute the total mass density and derivatives diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 4014a22581b..5a53ec5502f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -165,7 +165,7 @@ namespace geos arrayView1d const &localRhs) { GEOS_MARK_FUNCTION; - if (m_isThermal) + if (false && m_isThermal) { integer const useTotalMassEquation = 1; string const wellDofKey = dofManager.getKey(wellElementDofName()); @@ -177,7 +177,6 @@ namespace geos [&]( localIndex const, ElementSubRegionBase & subRegion ) { - ElementRegionManager const &elemManager = mesh.getElemManager(); string const dofKey = dofManager.getKey(CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString()); string const &fluidName = subRegion.getReference(viewKeyStruct::fluidNamesString()); From 384e29e01ceb241360a5e0a5a9199b3e455d054f Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:54:09 -0800 Subject: [PATCH 09/71] Load well prop ders in containers similar to reservoir --- .../wells/CompositionalMultiphaseWell.cpp | 48 ++++++++++++++----- .../CompositionalMultiphaseWellKernels.hpp | 11 ++++- ...rmalCompositionalMultiphaseWellKernels.hpp | 7 ++- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index a6fe21ab132..7ef48e66e24 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -246,9 +246,9 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) setSizedFromParent( 0 ). reference().resizeDimension< 0 >( m_numPhases ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ). + wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ). setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC + reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC //tjb -remove wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dPresString() ). @@ -595,16 +595,21 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & { return; } + using Deriv = multifluid::DerivativeOffset; integer const numComp = m_numComponents; localIndex const iwelemRef = subRegion.getTopWellElementIndex(); + string & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + fluidName = getConstitutiveName< MultiFluidBase >( subRegion ); + MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + integer isThermal = fluid.isThermal(); // subRegion data arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); arrayView1d< real64 > const & totalMassDens = subRegion.getField< fields::well::totalMassDensity >(); - arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDenss = subRegion.getField< fields::well::dTotalMassDensity >(); + arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens = subRegion.getField< fields::well::dTotalMassDensity >(); arrayView1d< real64 > const & dTotalMassDens_dPres = subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens_dCompDens = subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); @@ -630,9 +635,10 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [&numComp, + &isThermal, pres, totalMassDens, - dTotalMassDenss, + dTotalMassDens, dTotalMassDens_dPres, dTotalMassDens_dCompDens, wellElemGravCoef, @@ -643,14 +649,18 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & &iwelemRef, &refGravCoef] ( localIndex const ) { - GEOS_UNUSED_VAR( dTotalMassDenss ); - GEOS_UNUSED_VAR( dCurrentBHP ); real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef; dCurrentBHP_dPres = 1 + dTotalMassDens_dPres[iwelemRef] * diffGravCoef; + dCurrentBHP[Deriv::dP] = 1 + dTotalMassDens_dPres[iwelemRef] * diffGravCoef; for( integer ic = 0; ic < numComp; ++ic ) { dCurrentBHP_dCompDens[ic] = dTotalMassDens_dCompDens[iwelemRef][ic] * diffGravCoef; + dCurrentBHP[Deriv::dC+ic] = dTotalMassDens_dCompDens[iwelemRef][ic] * diffGravCoef; + } + if (isThermal ) + { + dCurrentBHP[Deriv::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef; } } ); @@ -690,7 +700,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - + integer isThermal = fluid.isThermal(); arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseFrac = fluid.phaseFraction(); arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dPhaseFrac = fluid.dPhaseFraction(); @@ -713,8 +723,8 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg arrayView1d< real64 > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); - arrayView1d< real64 > const & dCurrentPhaseVolRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); + arrayView2d< real64 > const & dCurrentPhaseVolRate = + wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); // tjb - remove arrayView1d< real64 > const & dCurrentPhaseVolRate_dPres = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); @@ -742,6 +752,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [&numComp, &numPhase, + &isThermal, fluidWrapper, pres, temp, @@ -774,8 +785,6 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg &massDensity] ( localIndex const ) { GEOS_UNUSED_VAR( massUnit ); - GEOS_UNUSED_VAR( dCurrentPhaseVolRate ); - GEOS_UNUSED_VAR( dCurrentTotalVolRate ); using Deriv = multifluid::DerivativeOffset; stackArray1d< real64, maxNumComp > work( numComp ); @@ -811,7 +820,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg // Step 2.1: compute the inverse of the total density and derivatives massDensity =totalDens[iwelemRef][0]; // need to verify this is surface dens real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; - real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; + stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); for( integer ic = 0; ic < numComp; ++ic ) { @@ -821,7 +830,15 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate currentTotalVolRate = currentTotalRate * totalDensInv; + // Compute derivatives dP dT + real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; dCurrentTotalVolRate_dPres = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; + dCurrentTotalVolRate[Deriv::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; + if ( isThermal ) + { + dCurrentTotalVolRate[Deriv::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv; + } + dCurrentTotalVolRate_dRate = totalDensInv; for( integer ic = 0; ic < numComp; ++ic ) { @@ -857,8 +874,15 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv; + dCurrentPhaseVolRate[ip][Deriv::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; dCurrentPhaseVolRate_dPres[ip] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; dCurrentPhaseVolRate_dRate[ip] = phaseFracTimesPhaseDensInv; + if ( isThermal ) + { + real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv + - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv; + dCurrentPhaseVolRate[ip][Deriv::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp; + } for( integer ic = 0; ic < numComp; ++ic ) { dCurrentPhaseVolRate_dCompDens[ip][ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index cf7a4990e2c..2cf329e239e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -542,6 +542,7 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne m_phaseMassDens( fluid.phaseMassDensity() ), m_dPhaseMassDens( fluid.dPhaseMassDensity() ), m_totalMassDens( subRegion.getField< fields::well::totalMassDensity >() ), + m_dTotalMassDens( subRegion.getField< fields::well::dTotalMassDensity >() ), m_dTotalMassDens_dPres( subRegion.getField< fields::well::dTotalMassDensity_dPressure >() ), m_dTotalMassDens_dCompDens( subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >() ) {} @@ -565,29 +566,36 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseMassDens = m_phaseMassDens[ei][0]; arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseMassDens = m_dPhaseMassDens[ei][0]; + real64 & totalMassDens = m_totalMassDens[ei]; + arraySlice1d< real64, compflow::USD_FLUID_DC - 1 > dTotalMassDens = m_dTotalMassDens[ei]; real64 & dTotalMassDens_dPres = m_dTotalMassDens_dPres[ei]; arraySlice1d< real64, compflow::USD_FLUID_DC - 1 > dTotalMassDens_dCompDens = m_dTotalMassDens_dCompDens[ei]; - real64 dMassDens_dC[numComp]{}; totalMassDens = 0.0; + dTotalMassDens[Deriv::dP]=0.0; dTotalMassDens_dPres = 0.0; + dTotalMassDens[Deriv::dP]=0.0; for( integer ic = 0; ic < numComp; ++ic ) { dTotalMassDens_dCompDens[ic] = 0.0; + dTotalMassDens[Deriv::dC+ic]=0.0; } for( integer ip = 0; ip < numPhase; ++ip ) { totalMassDens += phaseVolFrac[ip] * phaseMassDens[ip]; dTotalMassDens_dPres += dPhaseVolFrac[ip][Deriv::dP] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dP]; + dTotalMassDens[Deriv::dP] += dPhaseVolFrac[ip][Deriv::dP] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dP]; applyChainRule( numComp, dCompFrac_dCompDens, dPhaseMassDens[ip], dMassDens_dC, Deriv::dC ); for( integer ic = 0; ic < numComp; ++ic ) { dTotalMassDens_dCompDens[ic] += dPhaseVolFrac[ip][Deriv::dC+ic] * phaseMassDens[ip] + phaseVolFrac[ip] * dMassDens_dC[ic]; + dTotalMassDens[Deriv::dC+ic] += dPhaseVolFrac[ip][Deriv::dC+ic] * phaseMassDens[ip] + + phaseVolFrac[ip] * dMassDens_dC[ic]; } totalMassDensityKernelOp( ip ); //, phaseVolFrac, dTotalMassDens_dPres, dTotalMassDens_dCompDens ); @@ -612,6 +620,7 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne /// Views on total mass densities arrayView1d< real64 > m_totalMassDens; + arrayView2d< real64, compflow::USD_FLUID_DC > m_dTotalMassDens; arrayView1d< real64 > m_dTotalMassDens_dPres; arrayView2d< real64, compflow::USD_FLUID_DC > m_dTotalMassDens_dCompDens; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 818530789d1..62cb2d963b2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -45,6 +45,7 @@ namespace geos using Base::m_dCompFrac_dCompDens; using Base::m_dPhaseMassDens; using Base::m_dPhaseVolFrac; + using Base::m_dTotalMassDens; using Base::m_dTotalMassDens_dCompDens; using Base::m_dTotalMassDens_dPres; using Base::m_phaseMassDens; @@ -81,10 +82,14 @@ namespace geos arraySlice2d dPhaseMassDens = m_dPhaseMassDens[ei][0]; real64 &dTotalMassDens_dTemp = m_dTotalMassDens_dTemp[ei]; + real64 &dTotalMassDens_dT = m_dTotalMassDens[ei][Deriv::dT]; // Call the base compute the compute the total mass density and derivatives return Base::compute(ei, [&](localIndex const ip) - { dTotalMassDens_dTemp += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; }); + { + dTotalMassDens_dTemp += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; + dTotalMassDens_dT += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; + }); } protected: From 064cc07c7f9e3ba5c56b8ddf14f4832705bf9e7a Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:14:44 -0700 Subject: [PATCH 10/71] Added col indexing for well jacobian terms, includes specialization for thermal. Enabled kernels/ computes to be thermal aware via specialization or constexpr on template parameter. Most well terms have dt ders. Code tested on 3 standard isothermal models to smoke out offset errors. Lots of asserts left in code to ensure general storage arrays are correct eg.. (dProp[PresIndex]==dprop_dp).. these along with dprop_dp, dprop_dcomp etc arrays will be removed after most testing. Next step to add energy balance to well element flows and perf inflows --- .../constitutive/fluid/multifluid/Layouts.hpp | 28 + src/coreComponents/dataRepository/Group.hpp | 4 +- .../mesh/ElementRegionManager.hpp | 4 +- .../fluidFlow/CompositionalMultiphaseBase.cpp | 4 +- ...rmalCompositionalMultiphaseBaseKernels.hpp | 114 +- .../wells/CompositionalMultiphaseWell.cpp | 121 +- .../CompositionalMultiphaseWellFields.hpp | 18 +- .../CompositionalMultiphaseWellKernels.cpp | 409 +++++-- .../CompositionalMultiphaseWellKernels.hpp | 607 +++++++++- ...rmalCompositionalMultiphaseWellKernels.hpp | 1018 ++++++++++++----- .../fluidFlow/wells/WellSolverBase.cpp | 531 ++++++--- .../fluidFlow/wells/WellSolverBase.hpp | 2 +- 12 files changed, 2220 insertions(+), 640 deletions(-) diff --git a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp index 894fa58d041..c626ec6b20d 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp @@ -33,6 +33,7 @@ namespace multifluid { /// indices of pressure, temperature, and composition derivatives +// Fix me - if the order is changed the code crashes struct DerivativeOffset { /// index of derivative wrt pressure @@ -43,6 +44,33 @@ struct DerivativeOffset static integer constexpr dC = 2; }; +/// indices of pressure, temperature, and composition derivatives +template < integer NC , integer IS_THERMAL> +struct DerivativeOffsetC{}; + +template < integer NC > +struct DerivativeOffsetC +{ + /// index of derivative wrt pressure + static integer constexpr dP = 0; + /// index of derivative wrt temperature + static integer constexpr dT = dP + 1; + /// index of first derivative wrt compositions + static integer constexpr dC = dP+2; + /// number of derivatives + static integer constexpr nDer = NC + 2; +}; +template < integer NC > +struct DerivativeOffsetC +{ + /// index of derivative wrt pressure + static integer constexpr dP = 0; + /// index of first derivative wrt compositions + static integer constexpr dC = dP+1; + /// number of derivatives + static integer constexpr nDer = NC + 1; +}; + #if defined( GEOS_USE_DEVICE ) /// Constitutive model phase property array layout diff --git a/src/coreComponents/dataRepository/Group.hpp b/src/coreComponents/dataRepository/Group.hpp index 6090e17952c..3ba6eaef34c 100644 --- a/src/coreComponents/dataRepository/Group.hpp +++ b/src/coreComponents/dataRepository/Group.hpp @@ -29,7 +29,7 @@ #include -#include +#include #ifndef NOCHARTOSTRING_KEYLOOKUP /// macro definition to enable/disable char * lookups @@ -587,7 +587,7 @@ class Group void forSubGroups( LOOKUP_CONTAINER const & subGroupKeys, LAMBDA && lambda ) { localIndex counter = 0; - + for( auto const & subgroup : subGroupKeys ) { applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( getGroup( subgroup ), [&]( auto & castedSubGroup ) diff --git a/src/coreComponents/mesh/ElementRegionManager.hpp b/src/coreComponents/mesh/ElementRegionManager.hpp index a372b2df2fa..b94d6b08495 100644 --- a/src/coreComponents/mesh/ElementRegionManager.hpp +++ b/src/coreComponents/mesh/ElementRegionManager.hpp @@ -557,8 +557,8 @@ class ElementRegionManager : public ObjectManagerBase template< typename SUBREGIONTYPE, typename ... SUBREGIONTYPES, typename LOOKUP_CONTAINER, typename LAMBDA > void forElementSubRegions( LOOKUP_CONTAINER const & targetRegions, LAMBDA && lambda ) { - for (auto jj : targetRegions) - std::cout << "forElementSubRegions " << jj << std::endl; + for( auto jj : targetRegions ) + std::cout << "forElementSubRegions " << jj << std::endl; forElementSubRegionsComplete< SUBREGIONTYPE, SUBREGIONTYPES... >( targetRegions, [lambda = std::forward< LAMBDA >( lambda )]( localIndex const targetIndex, localIndex const, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index 00bb36f056d..6e09da364ff 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp @@ -1327,7 +1327,7 @@ void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( Dom ElementSubRegionBase const & subRegion ) { std::cout << "assembleAccumulationAndVolumeBalanceTerms : subregion " << subRegion.getName() << std::endl; - + string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); string const & solidName = subRegion.getReference< string >( viewKeyStruct::solidNamesString() ); @@ -2152,7 +2152,7 @@ void CompositionalMultiphaseBase::computeCFLNumbers( geos::DomainPartition & dom { typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); std::cout << "fluxApprox.forAllStencils : mesh " << mesh.getName() << std::endl; - + // While this kernel is waiting for a factory class, pass all the accessors here isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1 < isothermalCompositionalMultiphaseFVMKernels::CFLFluxKernel >( numComps, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp index 1d8956a66f8..b363ab08528 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp @@ -114,6 +114,52 @@ class PropertyKernelBase namespace internal { +template< typename T, typename LAMBDA > +void kernelLaunchSelectorCompThermSwitch( T value , bool const isThermal , LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); + + //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); + if ( isThermal ) + { + switch( value ) + { + case 1: + { + lambda( std::integral_constant< T, 1 >() , std::integral_constant< T, 1 >() ); return; } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >() , std::integral_constant< T, 1 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >() ,std::integral_constant< T, 1 >()); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } + } + else + { + switch( value ) + { + case 1: + { + lambda( std::integral_constant< T, 1 >() , std::integral_constant< T, 0 >() ); return; } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 0 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >() , std::integral_constant< T, 0 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 0 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >() ,std::integral_constant< T, 0 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } + } +} + template< typename T, typename LAMBDA > void kernelLaunchSelectorCompSwitch( T value, LAMBDA && lambda ) { @@ -768,12 +814,12 @@ class ElementBasedAssemblyKernel // check zero diagonal (works only in debug) /* - for( integer ic = 0; ic < numComp; ++ic ) - { - GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, + for( integer ic = 0; ic < numComp; ++ic ) + { + GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); - } - */ + } + */ } template< typename FUNC = NoOpFunc > @@ -2417,6 +2463,16 @@ struct HydrostaticPressureKernel /******************************** Kernel launch machinery ********************************/ + +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelectorCompTherm( integer const numComp, bool const isThermal , ARGS && ... args ) +{ + internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal , [&] ( auto NC , auto ISTHERMAL ) + { + KERNELWRAPPER::template launch< NC(), ISTHERMAL() >( std::forward< ARGS >( args )... ); + } ); +} + template< typename KERNELWRAPPER, typename ... ARGS > void KernelLaunchSelector1( integer const numComp, ARGS && ... args ) { @@ -2450,6 +2506,54 @@ void KernelLaunchSelector2( integer const numComp, integer const numPhase, ARGS } } +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelector_NC_NP_THERM( integer const numComp, integer const numPhase ,integer const isThermal, ARGS && ... args ) +{ + // Ideally this would be inside the dispatch, but it breaks on Summit with GCC 9.1.0 and CUDA 11.0.3. + if ( isThermal ) + { + if( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2, 1 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3, 1 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } + } + else + { + if( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2, 0 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3, 0 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } + } +} + } // namespace isothermalCompositionalMultiphaseBaseKernels } // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 7ef48e66e24..fb6922673f3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -148,7 +148,8 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) m_numComponents = fluid0.numFluidComponents(); m_isThermal = fluid0.isThermal(); } - m_numDofPerWellElement = m_isThermal ? m_numComponents + 3 : m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate + temp if thermal + m_numDofPerWellElement = m_isThermal ? m_numComponents + 3 : m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate + + // temp if thermal m_numDofPerResElement = m_isThermal ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure + NC compositions + temp if thermal // loop over the wells @@ -167,6 +168,8 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + + subRegion.registerField< fields::well::pressure >( getName() ); subRegion.registerField< fields::well::pressure_n >( getName() ); @@ -199,11 +202,11 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< fields::well::totalMassDensity >( getName() ); subRegion.registerField< fields::well::dTotalMassDensity >( getName() ). reference().resizeDimension< 1 >( m_numComponents +2 ); // dP, dT, dC - // tjb - remove + // tjb - remove subRegion.registerField< fields::well::dTotalMassDensity_dPressure >( getName() ); subRegion.registerField< fields::well::dTotalMassDensity_dGlobalCompDensity >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); - if ( fluid.isThermal() ) + if( fluid.isThermal() ) { subRegion.registerField< fields::well::dTotalMassDensity_dTemperature >( getName() ); } @@ -219,7 +222,7 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) perforationData.registerField< fields::well::compPerforationRate >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); perforationData.registerField< fields::well::dCompPerforationRate >( getName() ). - reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); + reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); // tjb - remove perforationData.registerField< fields::well::dCompPerforationRate_dPres >( getName() ). reference().resizeDimension< 1, 2 >( 2, m_numComponents ); @@ -228,12 +231,12 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) WellControls & wellControls = getWellControls( subRegion ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() ); - - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). + + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC + reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC - //tjb - remove + //tjb - remove wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentBHP_dPresString() ). setRestartFlags( RestartFlags::NO_WRITE ); //tjb - remove @@ -246,9 +249,9 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) setSizedFromParent( 0 ). reference().resizeDimension< 0 >( m_numPhases ); - wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ). + wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ). setSizedFromParent( 0 ). - reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents + 2 ); // dP, dT, dC + reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents + 3 ); // dP, dT, dC, dQ //tjb -remove wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dPresString() ). @@ -268,9 +271,9 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() ); - wellControls.registerWrapper >( viewKeyStruct::dCurrentTotalVolRateString() ). + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRateString() ). setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numComponents + 3 ); // dP, dT, dC dQ + reference().resizeDimension< 0 >( m_numComponents + 3 ); // dP, dT, dC dQ wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentTotalVolRate_dPresString() ). setRestartFlags( RestartFlags::NO_WRITE ); @@ -632,10 +635,13 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); arrayView1d< real64 > const & dCurrentBHP_dCompDens = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dCompDensString() ); + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal , [&] ( auto NC , auto ISTHERMAL ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr IS_THERMAL = ISTHERMAL(); // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [&numComp, - &isThermal, pres, totalMassDens, dTotalMassDens, @@ -658,11 +664,12 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & dCurrentBHP_dCompDens[ic] = dTotalMassDens_dCompDens[iwelemRef][ic] * diffGravCoef; dCurrentBHP[Deriv::dC+ic] = dTotalMassDens_dCompDens[iwelemRef][ic] * diffGravCoef; } - if (isThermal ) + if constexpr ( IS_THERMAL ) { dCurrentBHP[Deriv::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef; } } ); + }); if( logLevel >= 2 ) { @@ -735,8 +742,8 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg real64 & currentTotalVolRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); arrayView1d< real64 > const & dCurrentTotalVolRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); - // TJB - remove + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); + // TJB - remove real64 & dCurrentTotalVolRate_dPres = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); arrayView1d< real64 > const & dCurrentTotalVolRate_dCompDens = @@ -748,11 +755,14 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal , [&] ( auto NC , auto ISTHERMAL ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr IS_THERMAL = ISTHERMAL(); + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac; // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [&numComp, &numPhase, - &isThermal, fluidWrapper, pres, temp, @@ -786,7 +796,6 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg { GEOS_UNUSED_VAR( massUnit ); using Deriv = multifluid::DerivativeOffset; - stackArray1d< real64, maxNumComp > work( numComp ); // Step 1: evaluate the phase and total density in the reference element @@ -820,7 +829,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg // Step 2.1: compute the inverse of the total density and derivatives massDensity =totalDens[iwelemRef][0]; // need to verify this is surface dens real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; - + stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); for( integer ic = 0; ic < numComp; ++ic ) { @@ -833,16 +842,18 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg // Compute derivatives dP dT real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; dCurrentTotalVolRate_dPres = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; - dCurrentTotalVolRate[Deriv::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; - if ( isThermal ) + dCurrentTotalVolRate[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; + if constexpr ( IS_THERMAL ) { - dCurrentTotalVolRate[Deriv::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv; + dCurrentTotalVolRate[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv; } - + dCurrentTotalVolRate_dRate = totalDensInv; + dCurrentTotalVolRate[COFFSET_WJ::dQ] = dCurrentTotalVolRate_dRate; for( integer ic = 0; ic < numComp; ++ic ) { dCurrentTotalVolRate_dCompDens[ic] = currentTotalRate * dTotalDensInv_dCompDens[ic]; + dCurrentTotalVolRate[COFFSET_WJ::dC+ic] = currentTotalRate * dTotalDensInv_dCompDens[ic]; } if( logLevel >= 2 && useSurfaceConditions ) @@ -874,14 +885,15 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv; - dCurrentPhaseVolRate[ip][Deriv::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; dCurrentPhaseVolRate_dPres[ip] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; dCurrentPhaseVolRate_dRate[ip] = phaseFracTimesPhaseDensInv; - if ( isThermal ) + dCurrentPhaseVolRate[ip][COFFSET_WJ::dQ] = phaseFracTimesPhaseDensInv; + if constexpr (IS_THERMAL ) { real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv - - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv; - dCurrentPhaseVolRate[ip][Deriv::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp; + - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp; } for( integer ic = 0; ic < numComp; ++ic ) { @@ -890,6 +902,13 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg dCurrentPhaseVolRate_dCompDens[ip][ic] *= currentTotalRate; } applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dCurrentPhaseVolRate_dCompDens[ip], work.data() ); + for( integer ic = 0; ic < numComp; ++ic ) + { + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] *= currentTotalRate; + } + applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], &dCurrentPhaseVolRate[ip][COFFSET_WJ::dC], work.data() ); if( logLevel >= 2 && useSurfaceConditions ) { @@ -899,6 +918,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg } } } ); + } ) ; } ); } @@ -937,14 +957,14 @@ void CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegio string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - real64 maxDeltaPhaseVolFrac = + real64 maxDeltaPhaseVolFrac = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: PhaseVolumeFractionKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, subRegion, - fluid ) + fluid ) : isothermalCompositionalMultiphaseBaseKernels:: PhaseVolumeFractionKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, @@ -963,19 +983,19 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); fluid.isThermal() ? - thermalCompositionalMultiphaseWellKernels:: - TotalMassDensityKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_numComponents, - m_numPhases, - subRegion, - fluid ) - : + thermalCompositionalMultiphaseWellKernels:: + TotalMassDensityKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + subRegion, + fluid ) + : TotalMassDensityKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, subRegion, fluid ); - + } void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) @@ -985,10 +1005,10 @@ void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & s // update volumetric rates for the well constraints // note: this must be called before updateFluidModel - updateVolRatesForConstraint( subRegion ); // tjb - thermal +++ looks like it does a lot more... + updateVolRatesForConstraint( subRegion ); // tjb - thermal +++ looks like it does a lot more... // update densities, phase fractions, phase volume fractions - updateFluidModel( subRegion ); // Calculate fluid properties + updateFluidModel( subRegion ); // Calculate fluid properties updatePhaseVolumeFraction( subRegion ); // tjb - thermal updateTotalMassDensity( subRegion ); // tjb - thermal @@ -1465,6 +1485,10 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom WellControls const & wellControls = getWellControls( subRegion ); bool const disableReservoirToWellFlow = wellControls.isInjector() and !wellControls.isCrossflowEnabled(); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + bool isThermal = fluid.isThermal(); + PerforationData * const perforationData = subRegion.getPerforationData(); // get depth @@ -1480,7 +1504,7 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom subRegion.getField< fields::well::totalMassDensity >(); arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens = subRegion.getField< fields::well::dTotalMassDensity >(); - //tjb - remove + //tjb - remove arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres = subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = @@ -1500,7 +1524,7 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom perforationData->getField< fields::perforation::wellTransmissibility >(); arrayView2d< real64 > const & compPerfRate = - perforationData->getField< fields::well::compPerforationRate >(); + perforationData->getField< fields::well::compPerforationRate >(); arrayView4d< real64 > const & dCompPerfRate = perforationData->getField< fields::well::dCompPerforationRate >(); // tjb - remove @@ -1518,8 +1542,9 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom perforationData->getField< fields::perforation::reservoirElementIndex >(); isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector2< PerforationKernel >( numFluidComponents(), + KernelLaunchSelector_NC_NP_THERM< PerforationKernel >( numFluidComponents(), numFluidPhases(), + isThermal, perforationData->size(), disableReservoirToWellFlow, resCompFlowAccessors.get( fields::flow::pressure{} ), @@ -1714,6 +1739,10 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time WellControls & wellControls = getWellControls( subRegion ); + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + bool isThermal = fluid.isThermal(); // get the degrees of freedom, depth info, next welem index string const wellDofKey = dofManager.getKey( wellElementDofName() ); arrayView1d< globalIndex const > const & wellElemDofNumber = @@ -1736,15 +1765,15 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); - - bool controlHasSwitched = false; isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< PressureRelationKernel >( numFluidComponents(), + KernelLaunchSelectorCompTherm< PressureRelationKernel >( numFluidComponents(), isThermal, + //isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1< PressureRelationKernel >( numFluidComponents(), subRegion.size(), dofManager.rankOffset(), subRegion.isLocallyOwned(), subRegion.getTopWellElementIndex(), + isThermal, m_targetPhaseIndex, wellControls, time_n + dt, // controls evaluated with BHP/rate of the end of step diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp index 5b7481ae80c..f4279a195f9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp @@ -1,4 +1,4 @@ - /* +/* * ------------------------------------------------------------------------------------------------------------ * SPDX-License-Identifier: LGPL-2.1-only * @@ -113,22 +113,22 @@ DECLARE_FIELD( phaseVolumeFraction_n, WRITE_AND_READ, "Phase volume fraction at the previous converged time step" ); /* -DECLARE_FIELD( dCurrentBHP, - "dCurrentBHP", + DECLARE_FIELD( dCurrentBHP, + "dCurrentBHP", array1d< real64 >, 0, NOPLOT, NO_WRITE, "Derivative of current BHP with respect to pressure, temperature, and global component density" ); -DECLARE_FIELD( dCurrentPhaseVolRate, - "dCurrentPhaseVolRate", + DECLARE_FIELD( dCurrentPhaseVolRate, + "dCurrentPhaseVolRate", array2dLayoutPhase, 0, NOPLOT, NO_WRITE, "Derivative of current phase volume rate with respect to pressure, temperature, and global component density" ); -*/ + */ DECLARE_FIELD( totalMassDensity, "totalMassDensity", array1d< real64 >, @@ -138,7 +138,7 @@ DECLARE_FIELD( totalMassDensity, "Total mass density" ); DECLARE_FIELD( dTotalMassDensity, - "dTotalMassDensity", + "dTotalMassDensity", array2dLayoutFluid_dC, 0, NOPLOT, @@ -146,7 +146,7 @@ DECLARE_FIELD( dTotalMassDensity, "Derivative of total mass density with respect to pressure, temperature, and global component density" ); //tjb - remove -DECLARE_FIELD( dTotalMassDensity_dPressure, +DECLARE_FIELD( dTotalMassDensity_dPressure, "dTotalMassDensity_dPressure", array1d< real64 >, 0, @@ -160,7 +160,7 @@ DECLARE_FIELD( dTotalMassDensity_dTemperature, 0, NOPLOT, NO_WRITE, - "Derivative of total mass density with respect to temperature" ); + "Derivative of total mass density with respect to temperature" ); //tjb - remove DECLARE_FIELD( dTotalMassDensity_dGlobalCompDensity, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index a48b751dae8..6fbfdd57c67 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -119,7 +119,7 @@ ControlEquationHelper:: } } -template< integer NC > +template< integer NC , integer IS_THERMAL > GEOS_HOST_DEVICE inline void @@ -136,7 +136,7 @@ ControlEquationHelper:: real64 const & dCurrentBHP_dPres, arrayView1d< real64 const > const & dCurrentBHP_dCompDens, arrayView1d< real64 const > const & currentPhaseVolRate, - arrayView1d< real64 const > const & dCurrentPhaseVolRate, + arrayView2d< real64 const > const & dCurrentPhaseVolRate, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, @@ -151,9 +151,15 @@ ControlEquationHelper:: arrayView1d< real64 > const & localRhs ) { - GEOS_UNUSED_VAR(dCurrentBHP); - GEOS_UNUSED_VAR(dCurrentPhaseVolRate); - GEOS_UNUSED_VAR(dCurrentTotalVolRate); + //using ROFFSETC = compositionalMultiphaseWellKernels::RowOffsetComplete; + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac; + using Deriv = multifluid::DerivativeOffset; + //using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + //using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + GEOS_UNUSED_VAR( dCurrentBHP ); + GEOS_UNUSED_VAR( dCurrentPhaseVolRate ); + GEOS_UNUSED_VAR( dCurrentTotalVolRate ); localIndex const eqnRowIndex = dofNumber + ROFFSET::CONTROL - rankOffset; globalIndex const presDofColIndex = dofNumber + COFFSET::DPRES; globalIndex const rateDofColIndex = dofNumber + COFFSET::DCOMP + NC; @@ -168,6 +174,7 @@ ControlEquationHelper:: real64 dControlEqn_dPres = 0; real64 dControlEqn_dRate = 0; real64 dControlEqn_dComp[NC]{}; + real64 dControlEqn[NC+2+IS_THERMAL]{}; // Note: We assume in the computation of currentBHP that the reference elevation // is in the top well element. This is enforced by a check in the solver. @@ -181,43 +188,64 @@ ControlEquationHelper:: // control equation is a difference between current BHP and target BHP controlEqn = currentBHP - targetBHP; dControlEqn_dPres = dCurrentBHP_dPres; + dControlEqn[COFFSET_WJ::dP] = dCurrentBHP[Deriv::dP]; for( integer ic = 0; ic < NC; ++ic ) { dControlEqn_dComp[ic] = dCurrentBHP_dCompDens[ic]; + dControlEqn[COFFSET_WJ::dC+ic] = dCurrentBHP[Deriv::dC+ic]; } + if constexpr ( IS_THERMAL ) + + dControlEqn[COFFSET_WJ::dT] = dCurrentBHP[Deriv::dT]; + } // Oil volumetric rate control else if( currentControl == WellControls::Control::PHASEVOLRATE ) { controlEqn = currentPhaseVolRate[targetPhaseIndex] - targetPhaseRate; dControlEqn_dPres = dCurrentPhaseVolRate_dPres[targetPhaseIndex]; + dControlEqn[COFFSET_WJ::dP] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dP]; dControlEqn_dRate = dCurrentPhaseVolRate_dRate[targetPhaseIndex]; + dControlEqn[COFFSET_WJ::dQ] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dQ]; for( integer ic = 0; ic < NC; ++ic ) { dControlEqn_dComp[ic] = dCurrentPhaseVolRate_dCompDens[targetPhaseIndex][ic]; + dControlEqn[COFFSET_WJ::dC+ic] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dC+ic]; } + if constexpr ( IS_THERMAL ) + dControlEqn[COFFSET_WJ::dT] = dCurrentBHP[Deriv::dT]; } // Total volumetric rate control else if( currentControl == WellControls::Control::TOTALVOLRATE ) { controlEqn = currentTotalVolRate - targetTotalRate; dControlEqn_dPres = dCurrentTotalVolRate_dPres; + dControlEqn[COFFSET_WJ::dP] = dCurrentTotalVolRate[COFFSET_WJ::dP]; dControlEqn_dRate = dCurrentTotalVolRate_dRate; + dControlEqn[COFFSET_WJ::dQ] = dCurrentTotalVolRate[COFFSET_WJ::dQ]; for( integer ic = 0; ic < NC; ++ic ) { dControlEqn_dComp[ic] = dCurrentTotalVolRate_dCompDens[ic]; + dControlEqn[COFFSET_WJ::dC+ic] = dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; } + if constexpr ( IS_THERMAL ) + dControlEqn[COFFSET_WJ::dT] = dCurrentTotalVolRate[COFFSET_WJ::dT]; } // Total mass rate control else if( currentControl == WellControls::Control::MASSRATE ) { controlEqn = massDensity*currentTotalVolRate - targetMassRate; dControlEqn_dPres = massDensity*dCurrentTotalVolRate_dPres; + dControlEqn[COFFSET_WJ::dP] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dP]; dControlEqn_dRate = massDensity*dCurrentTotalVolRate_dRate; + dControlEqn[COFFSET_WJ::dQ] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dQ]; for( integer ic = 0; ic < NC; ++ic ) { dControlEqn_dComp[ic] = massDensity*dCurrentTotalVolRate_dCompDens[ic]; + dControlEqn[COFFSET_WJ::dC+ic] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; } + if constexpr ( IS_THERMAL ) + dControlEqn[COFFSET_WJ::dT] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dT]; } else { @@ -236,6 +264,12 @@ ControlEquationHelper:: compDofColIndices, dControlEqn_dComp, NC ); + // tjb- remove when safe and modify local matrix updates + assert(fabs( dControlEqn[COFFSET_WJ::dP] -dControlEqn_dPres) < FLT_EPSILON); + assert(fabs( dControlEqn[COFFSET_WJ::dQ] - dControlEqn_dRate ) < FLT_EPSILON); + for( integer ic=0; ic +template< integer NC , integer IS_THERMAL > GEOS_HOST_DEVICE void PressureRelationKernel:: @@ -582,22 +616,24 @@ PressureRelationKernel:: arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, real64 & localPresRel, - real64 ( & localPresRelJacobian )[2*(NC+1)] ) + real64 ( & localPresRelJacobian )[2*(NC+1 + IS_THERMAL)] ) { - GEOS_UNUSED_VAR(dTotalMassDens); - GEOS_UNUSED_VAR(dTotalMassDensNext); // local working variables and arrays real64 dAvgMassDens_dCompCurrent[NC]{}; real64 dAvgMassDens_dCompNext[NC]{}; // compute the average density at the interface between well elements real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); - real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDens_dPresNext; - real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens_dPres; + //real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDens_dPresNext; + //real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens_dPres; + real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDensNext[Deriv::dP]; + real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens[Deriv::dP]; for( integer ic = 0; ic < NC; ++ic ) { - dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDens_dCompDensNext[ic]; - dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens_dCompDens[ic]; + //dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDens_dCompDensNext[ic]; + //dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens_dCompDens[ic]; + dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDensNext[Deriv::dC+ic]; + dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens[Deriv::dC+ic]; } // compute depth diff times acceleration @@ -606,23 +642,32 @@ PressureRelationKernel:: // TODO: add friction and acceleration terms localPresRel = ( presNext - pres - avgMassDens * gravD ); - localPresRelJacobian[TAG::NEXT *(NC+1)] = ( 1 - dAvgMassDens_dPresNext * gravD ); + + // localPresRelJacbain contains dP, dC and potentially dT derivatives for neighboring well elements + // TAG::NEXT is 1, CURRENT is 0 , not sure why indexes are setup as below + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)] = ( 1 - dAvgMassDens_dPresNext * gravD ); localPresRelJacobian[TAG::CURRENT *(NC+1)] = ( -1 - dAvgMassDens_dPresCurrent * gravD ); for( integer ic = 0; ic < NC; ++ic ) { - localPresRelJacobian[TAG::NEXT *(NC+1) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; localPresRelJacobian[TAG::CURRENT *(NC+1) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; } + if constexpr ( IS_THERMAL ) + { + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDensNext[Deriv::dT]; + localPresRelJacobian[TAG::CURRENT *(NC+1)+1] = 0.5 * dTotalMassDens[Deriv::dT]; + } } -template< integer NC > +template< integer NC , integer IS_THERMAL > void PressureRelationKernel:: - launch( localIndex const size, + launch( localIndex const size, globalIndex const rankOffset, bool const isLocallyOwned, localIndex const iwelemControl, + bool const isThermal, integer const targetPhaseIndex, WellControls const & wellControls, real64 const & timeAtEndOfStep, @@ -638,7 +683,7 @@ PressureRelationKernel:: CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac; // static well control data bool const isProducer = wellControls.isProducer(); WellControls::Control const currentControl = wellControls.getControl(); @@ -651,7 +696,7 @@ PressureRelationKernel:: real64 const & currentBHP = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ); arrayView1d< real64 const > const & dCurrentBHP = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); // tjb - remove real64 const & dCurrentBHP_dPres = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); @@ -660,8 +705,8 @@ PressureRelationKernel:: arrayView1d< real64 const > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); - arrayView1d< real64 const > const & dCurrentPhaseVolRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); + arrayView2d< real64 const > const & dCurrentPhaseVolRate = + wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); // tjb - remove arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); @@ -673,7 +718,7 @@ PressureRelationKernel:: real64 const & currentTotalVolRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); arrayView1d< real64 const > const & dCurrentTotalVolRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); + wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); // tjb - remove real64 const & dCurrentTotalVolRate_dPres = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); @@ -709,8 +754,7 @@ PressureRelationKernel:: { switchControl.max( 1 ); } - - ControlEquationHelper::compute< NC >( rankOffset, + ControlEquationHelper::compute< NC, IS_THERMAL >( rankOffset, newControl, targetPhaseIndex, targetBHP, @@ -735,7 +779,6 @@ PressureRelationKernel:: wellElemDofNumber[iwelemControl], localMatrix, localRhs ); - // TODO: for consistency, we should assemble here, not in compute... } @@ -743,9 +786,10 @@ PressureRelationKernel:: { real64 localPresRel = 0; - real64 localPresRelJacobian[2*(NC+1)]{}; + real64 localPresRelJacobian[2*(NC+1+IS_THERMAL)]{}; - compute< NC >( wellElemGravCoef[iwelem], + compute< NC , IS_THERMAL >( + wellElemGravCoef[iwelem], wellElemGravCoef[iwelemNext], wellElemPressure[iwelem], wellElemPressure[iwelemNext], @@ -762,24 +806,28 @@ PressureRelationKernel:: // local working variables and arrays - globalIndex dofColIndices[2*(NC+1)]; + globalIndex dofColIndices[2*(NC+1+IS_THERMAL)]; globalIndex const eqnRowIndex = wellElemDofNumber[iwelem] + ROFFSET::CONTROL - rankOffset; - dofColIndices[TAG::NEXT *(NC+1)] = wellElemDofNumber[iwelemNext] + COFFSET::DPRES; - dofColIndices[TAG::CURRENT *(NC+1)] = wellElemDofNumber[iwelem] + COFFSET::DPRES; + dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL)] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dP; + dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL)] = wellElemDofNumber[iwelem] + COFFSET_WJ::dP; for( integer ic = 0; ic < NC; ++ic ) { - dofColIndices[TAG::NEXT *(NC+1) + ic+1] = wellElemDofNumber[iwelemNext] + COFFSET::DCOMP + ic; - dofColIndices[TAG::CURRENT *(NC+1) + ic+1] = wellElemDofNumber[iwelem] + COFFSET::DCOMP + ic; + dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dC + ic; + dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL) + ic+1] = wellElemDofNumber[iwelem] + COFFSET_WJ::dC + ic; + } + if constexpr ( IS_THERMAL ) + { + dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dT; + dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL)+NC+1] = wellElemDofNumber[iwelem] + COFFSET_WJ::dT; } - if( eqnRowIndex >= 0 && eqnRowIndex < localMatrix.numRows() ) { localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndex, dofColIndices, localPresRelJacobian, - 2 * (NC+1) ); + 2 * (NC+1+IS_THERMAL) ); RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndex], localPresRel ); } } @@ -787,13 +835,14 @@ PressureRelationKernel:: controlHasSwitched = ( switchControl.get() == 1 ); } -#define INST_PressureRelationKernel( NC ) \ +#define INST_PressureRelationKernel( NC , IS_THERMAL ) \ template \ void PressureRelationKernel:: \ - launch< NC >( localIndex const size, \ + launch< NC , IS_THERMAL >( localIndex const size, \ globalIndex const rankOffset, \ bool const isLocallyOwned, \ localIndex const iwelemControl, \ + bool const isThermal, \ integer const targetPhaseIndex, \ WellControls const & wellControls, \ real64 const & timeAtEndOfStep, \ @@ -809,16 +858,21 @@ PressureRelationKernel:: CRSMatrixView< real64, globalIndex const > const & localMatrix, \ arrayView1d< real64 > const & localRhs ) -INST_PressureRelationKernel( 1 ); -INST_PressureRelationKernel( 2 ); -INST_PressureRelationKernel( 3 ); -INST_PressureRelationKernel( 4 ); -INST_PressureRelationKernel( 5 ); +INST_PressureRelationKernel( 1, 0); +INST_PressureRelationKernel( 1, 1); +INST_PressureRelationKernel( 2, 0); +INST_PressureRelationKernel( 2, 1); +INST_PressureRelationKernel( 3, 0); +INST_PressureRelationKernel( 3, 1); +INST_PressureRelationKernel( 4, 0); +INST_PressureRelationKernel( 4 ,1); +INST_PressureRelationKernel( 5, 0); +INST_PressureRelationKernel( 5 ,1); /******************************** PerforationKernel ********************************/ -template< integer NC, integer NP > +template< integer NC, integer NP, integer IS_THERMAL > GEOS_HOST_DEVICE void PerforationKernel:: @@ -852,14 +906,14 @@ PerforationKernel:: arraySlice3d< real64 > const & dCompPerfRate_dComp ) { using Deriv = multifluid::DerivativeOffset; - GEOS_UNUSED_VAR(dWellElemTotalMassDens); - GEOS_UNUSED_VAR(dCompPerfRate); + using CP_Deriv = multifluid::DerivativeOffsetC; + GEOS_UNUSED_VAR( dCompPerfRate ); // local working variables and arrays real64 pres[2]{}; real64 dPres_dP[2]{}; real64 dPres_dC[2][NC]{}; real64 dFlux_dP[2]{}; - real64 dFlux_dC[2][NC]{}; + real64 dFlux_dC[2][NC]{}; real64 dMult_dP[2]{}; real64 dMult_dC[2][NC]{}; real64 dPotDiff_dP[2]{}; @@ -873,9 +927,19 @@ PerforationKernel:: real64 dMob_dC[NC]{}; real64 dCompFrac_dCompDens[NC]{}; - + // local working variables - compact + // All derivative quantiites generated are stored in arrays using CP_Deriv offsets + // The input well/reservoir quantites use the Deriv offsets + // The arrays using the deriv offsets have extra column for dT in isothermal cases + + real64 dPres[2][CP_Deriv::nDer]{}; + real64 dFlux[2][CP_Deriv::nDer]{}; + real64 dMob[CP_Deriv::nDer]{}; + real64 dPotDiff[2][CP_Deriv::nDer]{}; + real64 dCompFrac[CP_Deriv::nDer]{}; + // Step 1: reset the perforation rates - + // tjb - remove when safe for( integer ic = 0; ic < NC; ++ic ) { compPerfRate[ic] = 0.0; @@ -888,7 +952,17 @@ PerforationKernel:: } } } - + for( integer ic = 0; ic < NC; ++ic ) + { + compPerfRate[ic] = 0.0; + for( integer ke = 0; ke < 2; ++ke ) + { + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dCompPerfRate[ke][ic][jc] = 0.0; + } + } + } // Step 2: copy the variables from the reservoir and well element @@ -896,6 +970,7 @@ PerforationKernel:: pres[TAG::RES] = resPres; dPres_dP[TAG::RES] = 1.0; + dPres[TAG::RES][CP_Deriv::dP] = 1.0; multiplier[TAG::RES] = 1.0; // Here in the absence of a buoyancy term we assume that the reservoir cell is perforated at its center @@ -906,16 +981,25 @@ PerforationKernel:: pres[TAG::WELL] = wellElemPres; dPres_dP[TAG::WELL] = 1.0; + dPres[TAG::WELL][CP_Deriv::dP] = 1.0; multiplier[TAG::WELL] = -1.0; real64 const gravD = ( perfGravCoef - wellElemGravCoef ); pres[TAG::WELL] += wellElemTotalMassDens * gravD; + // Note RHS uses CP_Deriv while LHS uses Deriv !!! dPres_dP[TAG::WELL] += dWellElemTotalMassDens_dPres * gravD; + dPres[TAG::WELL][CP_Deriv::dP] += dWellElemTotalMassDens_dPres * gravD; + if constexpr ( IS_THERMAL ) + { + dPres[TAG::WELL][CP_Deriv::dT] += dWellElemTotalMassDens[Deriv::dT] * gravD; + } for( integer ic = 0; ic < NC; ++ic ) { dPres_dC[TAG::WELL][ic] += dWellElemTotalMassDens_dCompDens[ic] * gravD; + dPres[TAG::WELL][CP_Deriv::dC+ic] += dWellElemTotalMassDens[Deriv::dC+ic] * gravD; } + // Step 3: compute potential difference @@ -925,11 +1009,16 @@ PerforationKernel:: { potDiff += multiplier[i] * trans * pres[i]; dPotDiff_dP[i] += multiplier[i] * trans * dPres_dP[i]; - + for( integer ic = 0; ic < NC; ++ic ) { dPotDiff_dC[i][ic] += multiplier[i] * trans * dPres_dC[i][ic]; } + // LHS & RHS both use CP_Deriv + for ( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + { + dPotDiff[i][ic] += multiplier[i] * trans * dPres[i][ic]; + } } @@ -956,39 +1045,68 @@ PerforationKernel:: // density real64 const resDens = resPhaseDens[ip]; + real64 dDens[CP_Deriv::nDer]{}; + real64 const dResDens_dP = dResPhaseDens[ip][Deriv::dP]; + dDens[CP_Deriv::dP] = dResPhaseDens[ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dDens[CP_Deriv::dT] = dResPhaseDens[ip][Deriv::dT]; + } applyChainRule( NC, dResCompFrac_dCompDens, dResPhaseDens[ip], dDens_dC, Deriv::dC ); - + applyChainRule( NC, dResCompFrac_dCompDens, + dResPhaseDens[ip], + &dDens[CP_Deriv::dC], + Deriv::dC ); // viscosity real64 const resVisc = resPhaseVisc[ip]; + real64 dVisc[CP_Deriv::nDer]{}; real64 const dResVisc_dP = dResPhaseVisc[ip][Deriv::dP]; + dVisc[CP_Deriv::dP] = dResPhaseVisc[ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dVisc[CP_Deriv::dT] = dResPhaseVisc[ip][Deriv::dT]; + } applyChainRule( NC, dResCompFrac_dCompDens, dResPhaseVisc[ip], dVisc_dC, Deriv::dC ); + applyChainRule( NC, dResCompFrac_dCompDens, + dResPhaseVisc[ip], + &dVisc[CP_Deriv::dC], + Deriv::dC ); // relative permeability real64 const resRelPerm = resPhaseRelPerm[ip]; + real64 dRelPerm[CP_Deriv::nDer]{}; real64 dResRelPerm_dP = 0.0; for( integer jc = 0; jc < NC; ++jc ) { dRelPerm_dC[jc] = 0; } - + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dRelPerm[CP_Deriv::dC+jc]=0; + } for( integer jp = 0; jp < NP; ++jp ) { real64 const dResRelPerm_dS = dResPhaseRelPerm_dPhaseVolFrac[ip][jp]; dResRelPerm_dP += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - + dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dT]; + } for( integer jc = 0; jc < NC; ++jc ) { dRelPerm_dC[jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; + dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; } } - + // compute the reservoir phase mobility, including phase density real64 const resPhaseMob = resDens * resRelPerm / resVisc; real64 const dResPhaseMob_dPres = dResRelPerm_dP * resDens / resVisc @@ -998,6 +1116,12 @@ PerforationKernel:: dMob_dC[jc] = dRelPerm_dC[jc] * resDens / resVisc + resPhaseMob * (dDens_dC[jc] / resDens - dVisc_dC[jc] / resVisc); } + // Handles all dependencies + for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + { + dMob[jc] = dRelPerm[jc] * resDens / resVisc + + resPhaseMob * (dDens[jc] / resDens - dVisc[jc] / resVisc); + } // compute the phase flux and derivatives using upstream cell mobility flux = resPhaseMob * potDiff; @@ -1009,7 +1133,12 @@ PerforationKernel:: dFlux_dC[TAG::RES][ic] = dMob_dC[ic] * potDiff + resPhaseMob * dPotDiff_dC[TAG::RES][ic]; dFlux_dC[TAG::WELL][ic] = resPhaseMob * dPotDiff_dC[TAG::WELL][ic]; } - + // Handles all dependencies + for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + { + dFlux[TAG::RES][jc] = dMob[jc] * potDiff + resPhaseMob * dPotDiff[TAG::RES][jc]; + dFlux[TAG::WELL][jc] = resPhaseMob * dPotDiff[TAG::WELL][jc]; + } // increment component fluxes for( integer ic = 0; ic < NC; ++ic ) { @@ -1032,6 +1161,42 @@ PerforationKernel:: dCompPerfRate_dComp[TAG::WELL][ic][jc] += dFlux_dC[TAG::WELL][jc] * resPhaseCompFrac[ip][ic]; } } + // increment component fluxes + for( integer ic = 0; ic < NC; ++ic ) + { + // Note this needs to be uncommented out + //compPerfRate[ic] += flux * resPhaseCompFrac[ip][ic]; + dCompFrac[CP_Deriv::dP] = dResPhaseCompFrac[ip][ic][Deriv::dP]; + if constexpr (IS_THERMAL) + { + dCompFrac[CP_Deriv::dT] = dResPhaseCompFrac[ip][ic][Deriv::dT]; + } + + applyChainRule( NC, + dResCompFrac_dCompDens, + dResPhaseCompFrac[ip][ic], + &dCompFrac[CP_Deriv::dC], + Deriv::dC ); + + for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + { + dCompPerfRate[TAG::RES][ic][jc] += dFlux[TAG::RES][jc] * resPhaseCompFrac[ip][ic]; + dCompPerfRate[TAG::RES][ic][jc] += flux * dCompFrac[jc]; + dCompPerfRate[TAG::WELL][ic][jc] += dFlux[TAG::WELL][jc] * resPhaseCompFrac[ip][ic]; + } + } + } + + // tjb- remove when safe + for ( integer ic = 0; ic < NC; ic ++ ) + { + assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic]) < FLT_EPSILON); + assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic]) < FLT_EPSILON); + for ( integer jc = 0; jc < NC; ++jc) + { + assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc]) < FLT_EPSILON); + assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc]) < FLT_EPSILON); + } } } else // ** well is upstream ** @@ -1060,39 +1225,65 @@ PerforationKernel:: // viscosity real64 const resVisc = resPhaseVisc[ip]; + real64 dVisc[CP_Deriv::nDer]{}; real64 const dResVisc_dP = dResPhaseVisc[ip][Deriv::dP]; + dVisc[CP_Deriv::dP] = dResPhaseVisc[ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dVisc[CP_Deriv::dT] = dResPhaseVisc[ip][Deriv::dT]; + } applyChainRule( NC, dResCompFrac_dCompDens, dResPhaseVisc[ip], dVisc_dC, Deriv::dC ); - + applyChainRule( NC, dResCompFrac_dCompDens, + dResPhaseVisc[ip], + &dVisc[CP_Deriv::dC], + Deriv::dC ); + + // relative permeability real64 const resRelPerm = resPhaseRelPerm[ip]; + real64 dRelPerm[CP_Deriv::nDer]{}; real64 dResRelPerm_dP = 0.0; for( integer jc = 0; jc < NC; ++jc ) { dRelPerm_dC[jc] = 0; } - + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dRelPerm[jc]=0; + } for( integer jp = 0; jp < NP; ++jp ) { real64 const dResRelPerm_dS = dResPhaseRelPerm_dPhaseVolFrac[ip][jp]; dResRelPerm_dP += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - + dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dT]; + } for( integer jc = 0; jc < NC; ++jc ) { dRelPerm_dC[jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; + dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; } } - // increment total mobility resTotalMob += resRelPerm / resVisc; + dResTotalMob_dP += ( dResRelPerm_dP * resVisc - resRelPerm * dResVisc_dP ) / ( resVisc * resVisc ); for( integer ic = 0; ic < NC; ++ic ) { dResTotalMob_dC[ic] += ( dRelPerm_dC[ic] * resVisc - resRelPerm * dVisc_dC[ic] ) / ( resVisc * resVisc ); + } + // Handles all dependencies + for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + { + dMob[jc] += (dRelPerm[jc] *resVisc - resRelPerm * dVisc[jc] ) + / ( resVisc * resVisc); } } @@ -1101,13 +1292,28 @@ PerforationKernel:: real64 const mult = wellElemTotalDens * resTotalMob; dMult_dP[TAG::RES] = wellElemTotalDens * dResTotalMob_dP; dMult_dP[TAG::WELL] = 0.0; // because totalDens does not depend on pressure - for( integer ic = 0; ic < NC; ++ic ) { dMult_dC[TAG::RES][ic] = wellElemTotalDens * dResTotalMob_dC[ic]; dMult_dC[TAG::WELL][ic] = resTotalMob; } + real64 dMult[2][CP_Deriv::nDer]{}; + dMult[TAG::WELL][CP_Deriv::dP] = 0.0; + if constexpr ( IS_THERMAL ) + { + dMult[TAG::WELL][CP_Deriv::dT] = 0.0; + } + for ( integer ic = 0; ic < NC; ++ic ) + { + dMult[TAG::WELL][CP_Deriv::dC+ic] = resTotalMob; + } + for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dMult[TAG::RES][jc] = wellElemTotalDens * dMob[jc]; + } + + // compute the volumetric flux and derivatives using upstream cell mobility flux = mult * potDiff; dFlux_dP[TAG::RES] = dMult_dP[TAG::RES] * potDiff + mult * dPotDiff_dP[TAG::RES]; @@ -1118,7 +1324,12 @@ PerforationKernel:: dFlux_dC[TAG::RES][ic] = dMult_dC[TAG::RES][ic] * potDiff + mult * dPotDiff_dC[TAG::RES][ic]; dFlux_dC[TAG::WELL][ic] = dMult_dC[TAG::WELL][ic] * potDiff + mult * dPotDiff_dC[TAG::WELL][ic]; } - + + for ( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + { + dFlux[TAG::RES][ic] = dMult[TAG::RES][ic] * potDiff + mult * dPotDiff[TAG::RES][ic]; + dFlux[TAG::WELL][ic] = dMult[TAG::WELL][ic] * potDiff + mult * dPotDiff[TAG::WELL][ic]; + } // compute component fluxes for( integer ic = 0; ic < NC; ++ic ) { @@ -1133,10 +1344,47 @@ PerforationKernel:: dCompPerfRate_dComp[TAG::WELL][ic][jc] += dWellElemCompFrac_dCompDens[ic][jc] * flux; } } + for( integer ic = 0; ic < NC; ++ic ) + { + // Note this needs to be include below when this code above is removed + //compPerfRate[ic] += wellElemCompFrac[ic] * flux; + for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dCompPerfRate[TAG::RES][ic][jc] = wellElemCompFrac[ic] * dFlux[TAG::RES][jc]; + } + } + for( integer ic = 0; ic < NC; ++ic ) + { + dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] = wellElemCompFrac[ic] * dFlux[TAG::WELL][CP_Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dCompPerfRate[TAG::WELL][ic][CP_Deriv::dT] = wellElemCompFrac[ic] * dFlux[TAG::WELL][CP_Deriv::dT]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] += wellElemCompFrac[ic] * dFlux[TAG::WELL][CP_Deriv::dC+jc]; + dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] += dWellElemCompFrac_dCompDens[ic][jc] * flux; + } + } + // tjb- remove when safe + for ( integer ic = 0; ic < NC; ic ++ ) + { + if (fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic]) > FLT_EPSILON) + { + std::cout << ic << " " << dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] << " " << dCompPerfRate_dPres[TAG::RES][ic] << std::endl; + } + assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic]) < FLT_EPSILON); + assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic]) < FLT_EPSILON); + for ( integer jc = 0; jc < NC; ++jc) + { + assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc]) < FLT_EPSILON); + assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc]) < FLT_EPSILON); + } + } } } -template< integer NC, integer NP > +template< integer NC, integer NP , integer IS_THERMAL> void PerforationKernel:: launch( localIndex const size, @@ -1186,7 +1434,7 @@ PerforationKernel:: // get the index of the well elem localIndex const iwelem = perfWellElemIndex[iperf]; - compute< NC, NP >( disableReservoirToWellFlow, + compute< NC, NP, IS_THERMAL >( disableReservoirToWellFlow, resPres[er][esr][ei], resPhaseVolFrac[er][esr][ei], dResPhaseVolFrac[er][esr][ei], @@ -1218,10 +1466,10 @@ PerforationKernel:: } ); } -#define INST_PerforationKernel( NC, NP ) \ +#define INST_PerforationKernel( NC, NP, IS_THERMAL ) \ template \ void PerforationKernel:: \ - launch< NC, NP >( localIndex const size, \ + launch< NC, NP, IS_THERMAL >( localIndex const size, \ bool const disableReservoirToWellFlow, \ ElementViewConst< arrayView1d< real64 const > > const & resPres, \ ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, \ @@ -1255,17 +1503,26 @@ PerforationKernel:: arrayView3d< real64 > const & dCompPerfRate_dPres, \ arrayView4d< real64 > const & dCompPerfRate_dComp ) -INST_PerforationKernel( 1, 2 ); -INST_PerforationKernel( 2, 2 ); -INST_PerforationKernel( 3, 2 ); -INST_PerforationKernel( 4, 2 ); -INST_PerforationKernel( 5, 2 ); -INST_PerforationKernel( 1, 3 ); -INST_PerforationKernel( 2, 3 ); -INST_PerforationKernel( 3, 3 ); -INST_PerforationKernel( 4, 3 ); -INST_PerforationKernel( 5, 3 ); - +INST_PerforationKernel( 1, 2 , 0 ); +INST_PerforationKernel( 2, 2 , 0 ); +INST_PerforationKernel( 3, 2 , 0 ); +INST_PerforationKernel( 4, 2 , 0 ); +INST_PerforationKernel( 5, 2 , 0 ); +INST_PerforationKernel( 1, 3 , 0 ); +INST_PerforationKernel( 2, 3 , 0 ); +INST_PerforationKernel( 3, 3 , 0 ); +INST_PerforationKernel( 4, 3 , 0 ); +INST_PerforationKernel( 5, 3 , 0 ); +INST_PerforationKernel( 1, 2 , 1 ); +INST_PerforationKernel( 2, 2 , 1 ); +INST_PerforationKernel( 3, 2 , 1 ); +INST_PerforationKernel( 4, 2 , 1 ); +INST_PerforationKernel( 5, 2 , 1 ); +INST_PerforationKernel( 1, 3 , 1 ); +INST_PerforationKernel( 2, 3 , 1 ); +INST_PerforationKernel( 3, 3 , 1 ); +INST_PerforationKernel( 4, 3 , 1 ); +INST_PerforationKernel( 5, 3 , 1 ); /******************************** AccumulationKernel ********************************/ template< integer NC > @@ -1482,7 +1739,7 @@ VolumeBalanceKernel:: localVolBalance = 1.0; for( integer ic = 0; ic < NC+1; ++ic ) { - localVolBalanceJacobian[ic] = 0.0; + localVolBalanceJacobian[ic] = 0.0; } // sum contributions to component accumulation from each phase diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 2cf329e239e..8e4eb98d267 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -67,6 +67,15 @@ struct ColOffset static constexpr integer DCOMP = 1; }; +template < integer NC > +struct ColOffset_WellJac +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static constexpr integer dT = dQ+1; +}; + // define the row offset of the residual equations struct RowOffset { @@ -74,11 +83,17 @@ struct RowOffset static constexpr integer MASSBAL = 1; }; +template < integer NC > +struct RowOffset_WellJac +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer ENERGYBAL = VOLBAL+1; +}; /******************************** ControlEquationHelper ********************************/ - struct ControlEquationHelper { - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; using COFFSET = compositionalMultiphaseWellKernels::ColOffset; @@ -98,7 +113,7 @@ struct ControlEquationHelper real64 const & currentTotalVolRate, WellControls::Control & newControl ); - template< integer NC > + template< integer NC , integer IS_THERMAL > GEOS_HOST_DEVICE inline static void @@ -114,7 +129,7 @@ struct ControlEquationHelper real64 const & dCurrentBHP_dPres, arrayView1d< real64 const > const & dCurrentBHP_dCompDens, arrayView1d< real64 const > const & currentPhaseVolRate, - arrayView1d< real64 const > const & dCurrentPhaseVolRate, + arrayView2d< real64 const > const & dCurrentPhaseVolRate, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, @@ -186,12 +201,12 @@ struct FluxKernel struct PressureRelationKernel { - + using Deriv = multifluid::DerivativeOffset; using TAG = compositionalMultiphaseWellKernels::ElemTag; using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - template< integer NC > + template< integer NC ,integer IS_THERMAL > GEOS_HOST_DEVICE inline static void @@ -208,14 +223,15 @@ struct PressureRelationKernel arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, real64 & localPresRel, - real64 ( &localPresRelJacobian )[2*(NC+1)] ); + real64 ( &localPresRelJacobian )[2*(NC+1+IS_THERMAL)] ); - template< integer NC > + template< integer NC , integer IS_THERMAL > static void launch( localIndex const size, globalIndex const rankOffset, bool const isLocallyOwned, localIndex const iwelemControl, + bool const isThermal, integer const targetPhaseIndex, WellControls const & wellControls, real64 const & timeAtEndOfStep, @@ -272,7 +288,7 @@ struct PerforationKernel using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - template< integer NC, integer NP > + template< integer NC, integer NP , integer IS_THERMAL> GEOS_HOST_DEVICE inline static void @@ -305,7 +321,7 @@ struct PerforationKernel arraySlice2d< real64 > const & dCompPerfRate_dPres, arraySlice3d< real64 > const & dCompPerfRate_dComp ); - template< integer NC, integer NP > + template< integer NC, integer NP, integer IS_THERMAL > static void launch( localIndex const size, bool const disableReservoirToWellFlow, @@ -574,7 +590,7 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne real64 dMassDens_dC[numComp]{}; totalMassDens = 0.0; - dTotalMassDens[Deriv::dP]=0.0; + dTotalMassDens[Deriv::dP]=0.0; dTotalMassDens_dPres = 0.0; dTotalMassDens[Deriv::dP]=0.0; for( integer ic = 0; ic < numComp; ++ic ) @@ -1029,7 +1045,8 @@ template< integer NUM_COMP, integer NUM_DOF > class ElementBasedAssemblyKernel { public: - + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; /// Compile time value for the number of components static constexpr integer numComp = NUM_COMP; @@ -1097,7 +1114,9 @@ class ElementBasedAssemblyKernel localIndex localRow = -1; /// Indices of the matrix rows/columns corresponding to the dofs in this element - globalIndex dofIndices[numDof]{}; + globalIndex dofIndices[numDof]{}; + globalIndex eqnRowIndices[numComp+1]{}; + globalIndex dofColIndices[numComp+1]{}; /// C-array storage for the element local residual vector (all equations except volume balance) real64 localResidual[numEqn]{}; @@ -1127,14 +1146,29 @@ class ElementBasedAssemblyKernel StackVariables & stack ) const { // initialize the volume - stack.volume = m_volume[ei]; - - // set row index and degrees of freedom indices for this element - stack.localRow = m_dofNumber[ei] - m_rankOffset; - for( integer idof = 0; idof < numDof; ++idof ) + stack.volume = m_volume[ei]; + // set row index and degrees of freedom indices for this element (mass + vol bal) + for( integer ic = 0; ic < numComp+1; ++ic ) + { + stack.eqnRowIndices[ic] = m_dofNumber[ei] + ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // set DOF col indices for this block ( mass + vol bal) + for( integer idof = 0; idof < numComp+1; ++idof ) + { + stack.dofColIndices[idof] = m_dofNumber[ei] + COFFSET::DPRES + idof; + } + if ( 0) + for ( integer jc = 0; jc < numEqn; ++jc ) { - stack.dofIndices[idof] = m_dofNumber[ei] + idof; + stack.localResidual[jc] = 0.0; + for ( integer ic = 0; ic < numDof; ++ic ) + { + stack.localJacobian[jc][ic] = 0.0; + } + } + } /** @@ -1179,7 +1213,7 @@ class ElementBasedAssemblyKernel real64 const phaseAmount_n = stack.volume * phaseVolFrac_n[ip] * phaseDens_n[ip]; real64 const dPhaseAmount_dP = stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] - + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); + + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); // assemble density dependence applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); @@ -1225,12 +1259,12 @@ class ElementBasedAssemblyKernel // check zero diagonal (works only in debug) /* - for( integer ic = 0; ic < numComp; ++ic ) - { - GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, + for( integer ic = 0; ic < numComp; ++ic ) + { + GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); - } - */ + } + */ } @@ -1273,11 +1307,11 @@ class ElementBasedAssemblyKernel // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) stack.localResidual[numComp] = stack.volume * oneMinusPhaseVolFracSum; - for( integer idof = 0; idof < numDof; ++idof ) + for( integer idof = 0; idof < numComp+1; ++idof ) { stack.localJacobian[numComp][idof] *= stack.volume; } - + } /** @@ -1291,11 +1325,12 @@ class ElementBasedAssemblyKernel { using namespace compositionalMultiphaseUtilities; + if( m_kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) { // apply equation/variable change transformation to the component mass balance equations - real64 work[numDof]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localJacobian, work ); + real64 work[numComp + 1]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp+1, stack.localJacobian, work ); shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localResidual ); } @@ -1306,12 +1341,13 @@ class ElementBasedAssemblyKernel integer const numRows = numComp+1; for( integer i = 0; i < numRows; ++i ) { - m_localRhs[stack.localRow + i] += stack.localResidual[i]; - m_localMatrix.addToRow< serialAtomic >( stack.localRow + i, - stack.dofIndices, + m_localRhs[stack.eqnRowIndices[i]] += stack.localResidual[i]; + m_localMatrix.addToRow< serialAtomic >( stack.eqnRowIndices[i], + stack.dofColIndices, stack.localJacobian[i], - numDof ); + numComp+1 ); } + } /** @@ -1396,11 +1432,516 @@ class ElementBasedAssemblyKernel BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const m_kernelFlags; }; + /** * @class ElementBasedAssemblyKernelFactory */ +class ElementBasedAssemblyKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( localIndex const numComps, + localIndex const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + localIndex constexpr NUM_COMP = NC(); + localIndex constexpr NUM_DOF = NC()+2; + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + + ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > + kernel( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); + ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); + } ); + } +}; +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NC, integer NUM_DOF > +class FaceBasedAssemblyKernel +{ +public: + + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using TAG = compositionalMultiphaseWellKernels::ElemTag; + + + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + FaceBasedAssemblyKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellControls const & wellControls, + ElementSubRegionBase const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + : + m_dt( dt ), + m_rankOffset( rankOffset ), + m_wellElemDofNumber ( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), + m_nextWellElemIndex ( subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString()) ), + m_connRate ( subRegion.getField< fields::well::mixtureConnectionRate >() ), + m_wellElemCompFrac ( subRegion.getField< fields::well::globalCompFraction >() ), + m_dWellElemCompFrac_dCompDens ( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ), + m_localMatrix( localMatrix ), + m_localRhs ( localRhs ), + m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ), + m_isProducer ( wellControls.isProducer() ), + m_injection ( wellControls.getInjectionStream() ) + { } + + + GEOS_HOST_DEVICE + inline + void + computeExit( real64 const & dt, + real64 const ( &compFlux )[NC], + real64 const ( &dCompFlux_dRate )[NC], + real64 const ( &dCompFlux_dPresUp )[NC], + real64 const ( &dCompFlux_dCompDensUp )[NC][NC], + real64 ( & oneSidedFlux )[NC], + real64 ( & oneSidedFluxJacobian_dRate )[NC][1], + real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ) const + { + for( integer ic = 0; ic < NC; ++ic ) + { + oneSidedFlux[ic] = -dt * compFlux[ic]; + + // derivative with respect to rate + oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; + // derivative with respect to upstream pressure + oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; + + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; + } + } + } + GEOS_HOST_DEVICE + inline + void + compute( real64 const & dt, + real64 const ( &compFlux )[NC], + real64 const ( &dCompFlux_dRate )[NC], + real64 const ( &dCompFlux_dPresUp )[NC], + real64 const ( &dCompFlux_dCompDensUp )[NC][NC], + real64 ( & localFlux )[2*NC], + real64 ( & localFluxJacobian_dRate )[2*NC][1], + real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ) const + { + // flux terms + for( integer ic = 0; ic < NC; ++ic ) + { + localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; + localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; + + // derivative with respect to rate + localFluxJacobian_dRate[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dRate[ic]; + localFluxJacobian_dRate[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dRate[ic]; + + // derivative with respect to upstream pressure + localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dPresUp[ic]; + localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dPresUp[ic]; + + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; + localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; + } + } + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iwelem, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + using namespace compositionalMultiphaseUtilities; + + // create local work arrays + real64 compFracUp[NC]{}; + real64 dCompFrac_dCompDensUp[NC][NC]{}; + + real64 compFlux[NC]{}; + real64 dCompFlux_dRate[NC]{}; + real64 dCompFlux_dPresUp[NC]{}; + real64 dCompFlux_dCompDensUp[NC][NC]{}; + + // Step 1) decide the upwind well element + + /* currentConnRate < 0 flow from iwelem to iwelemNext + * currentConnRate > 0 flow from iwelemNext to iwelem + * With this convention, currentConnRate < 0 at the last connection for a producer + * currentConnRate > 0 at the last connection for a injector + */ + + localIndex const iwelemNext = m_nextWellElemIndex[iwelem]; + real64 const currentConnRate = m_connRate[iwelem]; + localIndex iwelemUp = -1; + + if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + { + // we still need to define iwelemUp for Jacobian assembly + iwelemUp = iwelem; + + // just copy the injection stream into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_injection[ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFrac_dCompDensUp[ic][jc] = 0.0; + } + } + } + else + { + // first set iwelemUp to the upstream cell + if( ( iwelemNext < 0 && m_isProducer ) // exit connection, producer + || currentConnRate < 0 ) // not an exit connection, iwelem is upstream + { + iwelemUp = iwelem; + } + else // not an exit connection, iwelemNext is upstream + { + iwelemUp = iwelemNext; + } + + // copy the vars of iwelemUp into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_wellElemCompFrac[iwelemUp][ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFrac_dCompDensUp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + } + } + } + + // Step 2) compute upstream transport coefficient + + for( integer ic = 0; ic < NC; ++ic ) + { + compFlux[ic] = compFracUp[ic] * currentConnRate; + dCompFlux_dRate[ic] = compFracUp[ic]; + dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; + } + } + + globalIndex const offsetUp = m_wellElemDofNumber[iwelemUp]; + globalIndex const offsetCurrent = m_wellElemDofNumber[iwelem]; + + if( iwelemNext < 0 ) // exit connection + { + // for this case, we only need NC mass conservation equations + // so we do not use the arrays initialized before the loop + real64 oneSidedFlux[NC]{}; + real64 oneSidedFluxJacobian_dRate[NC][1]{}; + real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; + + computeExit ( m_dt, + compFlux, + dCompFlux_dRate, + dCompFlux_dPresUp, + dCompFlux_dCompDensUp, + oneSidedFlux, + oneSidedFluxJacobian_dRate, + oneSidedFluxJacobian_dPresCompUp ); + + + globalIndex oneSidedEqnRowIndices[NC]{}; + globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; + globalIndex oneSidedDofColIndices_dRate = 0; + + // jacobian indices + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + oneSidedEqnRowIndices[ic] = offsetUp + ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // in the dof ordering used in this class, there are 1 pressure dofs + // and NC compDens dofs before the rate dof in this block + localIndex const dRateColOffset = COFFSET::DCOMP + NC; + oneSidedDofColIndices_dRate = offsetCurrent + dRateColOffset; + + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + // dofs are the **upstream** pressure and component densities + oneSidedDofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; + } + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NC + 1]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); + } + + for( integer i = 0; i < NC; ++i ) + { + if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + &oneSidedDofColIndices_dRate, + oneSidedFluxJacobian_dRate[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + oneSidedDofColIndices_dPresCompUp, + oneSidedFluxJacobian_dPresCompUp[i], + NC+1 ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); + } + } + } + else // not an exit connection + { + real64 localFlux[2*NC]{}; + real64 localFluxJacobian_dRate[2*NC][1]{}; + real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; + + compute( m_dt, + compFlux, + dCompFlux_dRate, + dCompFlux_dPresUp, + dCompFlux_dCompDensUp, + localFlux, + localFluxJacobian_dRate, + localFluxJacobian_dPresCompUp ); + + + globalIndex eqnRowIndices[2*NC]{}; + globalIndex dofColIndices_dPresCompUp[NC+1]{}; + globalIndex dofColIndices_dRate = 0; + + globalIndex const offsetNext = m_wellElemDofNumber[iwelemNext]; + + // jacobian indices + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + eqnRowIndices[TAG::NEXT *NC+ic] = offsetNext + ROFFSET::MASSBAL + ic - m_rankOffset; + eqnRowIndices[TAG::CURRENT *NC+ic] = offsetCurrent + ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // in the dof ordering used in this class, there are 1 pressure dofs + // and NC compDens dofs before the rate dof in this block + localIndex const dRateColOffset = COFFSET::DCOMP + NC; + dofColIndices_dRate = offsetCurrent + dRateColOffset; + + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + // dofs are the **upstream** pressure and component densities + dofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; + } + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NC + 1]{}; + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); + } + + for( integer i = 0; i < 2*NC; ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], + &dofColIndices_dRate, + localFluxJacobian_dRate[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices_dPresCompUp, + localFluxJacobian_dPresCompUp[i], + NC+1 ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localFlux[i] ); + } + } + } + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + //typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + // kernelComponent.numPointsInFlux( iconn ) ); + + //kernelComponent.setup( iconn, stack ); + kernelComponent.computeFlux( ie ); + //kernelComponent.complete( iconn, stack ); + } ); + } + +protected: + /// Time step size + real64 const m_dt; + /// Rank offset for calculating row/col Jacobian indices + integer const m_rankOffset; + + /// Reference to the degree-of-freedom numbers + arrayView1d< globalIndex const > const m_wellElemDofNumber; + /// Next element index, needed since iterating over element nodes, not edges + arrayView1d< localIndex const > const m_nextWellElemIndex; + + /// Connection rate + arrayView1d< real64 const > const m_connRate; + + /// Element component fraction + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; + /// Element component fraction derivatives + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + /// Kernel option flag + integer const m_useTotalMassEquation; + + /// Well type + bool const m_isProducer; + + /// Injection stream composition + arrayView1d< real64 const > const m_injection; + + +}; + +/** + * @class FaceBasedAssemblyKernelFactory + */ +class FaceBasedAssemblyKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + real64 const dt, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + WellControls const & wellControls, + ElementSubRegionBase const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 2; + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + + + using kernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF >; + + + kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } +}; } // end namespace compositionalMultiphaseWellKernels } // end namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 62cb2d963b2..2e04d48d829 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -24,226 +24,225 @@ namespace geos { - namespace thermalCompositionalMultiphaseWellKernels +namespace thermalCompositionalMultiphaseWellKernels +{ + +using namespace constitutive; + +/******************************** TotalMassDensityKernel ****************************/ + +/** + * @class TotalMassDensityKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Define the interface for the property kernel in charge of computing the total mass density + */ +template< integer NUM_COMP, integer NUM_PHASE > +class TotalMassDensityKernel : public compositionalMultiphaseWellKernels::TotalMassDensityKernel< NUM_COMP, NUM_PHASE > +{ +public: + using Base = compositionalMultiphaseWellKernels::TotalMassDensityKernel< NUM_COMP, NUM_PHASE >; + using Base::m_dCompFrac_dCompDens; + using Base::m_dPhaseMassDens; + using Base::m_dPhaseVolFrac; + using Base::m_dTotalMassDens; + using Base::m_dTotalMassDens_dCompDens; + using Base::m_dTotalMassDens_dPres; + using Base::m_phaseMassDens; + using Base::m_phaseVolFrac; + using Base::m_totalMassDens; + using Base::numComp; + using Base::numPhase; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + TotalMassDensityKernel( ObjectManagerBase & subRegion, + MultiFluidBase const & fluid ) + : Base( subRegion, fluid ), + m_dTotalMassDens_dTemp( subRegion.getField< fields::well::dTotalMassDensity_dTemperature >()) + {} + + /** + * @brief Compute the total mass density in an element + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[in] totalMassDensityKernelOp the function used to customize the kernel + */ + GEOS_HOST_DEVICE inline void compute( localIndex const ei ) const { + using Deriv = multifluid::DerivativeOffset; - using namespace constitutive; + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseMassDens = m_phaseMassDens[ei][0]; + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseMassDens = m_dPhaseMassDens[ei][0]; - /******************************** TotalMassDensityKernel ****************************/ + real64 & dTotalMassDens_dTemp = m_dTotalMassDens_dTemp[ei]; + real64 & dTotalMassDens_dT = m_dTotalMassDens[ei][Deriv::dT]; - /** - * @class TotalMassDensityKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_PHASE number of fluid phases - * @brief Define the interface for the property kernel in charge of computing the total mass density - */ - template - class TotalMassDensityKernel : public compositionalMultiphaseWellKernels::TotalMassDensityKernel + // Call the base compute the compute the total mass density and derivatives + return Base::compute( ei, [&]( localIndex const ip ) { - public: - using Base = compositionalMultiphaseWellKernels::TotalMassDensityKernel; - using Base::m_dCompFrac_dCompDens; - using Base::m_dPhaseMassDens; - using Base::m_dPhaseVolFrac; - using Base::m_dTotalMassDens; - using Base::m_dTotalMassDens_dCompDens; - using Base::m_dTotalMassDens_dPres; - using Base::m_phaseMassDens; - using Base::m_phaseVolFrac; - using Base::m_totalMassDens; - using Base::numComp; - using Base::numPhase; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - TotalMassDensityKernel(ObjectManagerBase &subRegion, - MultiFluidBase const &fluid) - : Base(subRegion, fluid), - m_dTotalMassDens_dTemp(subRegion.getField()) - { - } - - /** - * @brief Compute the total mass density in an element - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[in] totalMassDensityKernelOp the function used to customize the kernel - */ - GEOS_HOST_DEVICE inline void compute(localIndex const ei) const - { - using Deriv = multifluid::DerivativeOffset; - - arraySlice1d phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d dPhaseVolFrac = m_dPhaseVolFrac[ei]; - arraySlice1d phaseMassDens = m_phaseMassDens[ei][0]; - arraySlice2d dPhaseMassDens = m_dPhaseMassDens[ei][0]; - - real64 &dTotalMassDens_dTemp = m_dTotalMassDens_dTemp[ei]; - real64 &dTotalMassDens_dT = m_dTotalMassDens[ei][Deriv::dT]; - - // Call the base compute the compute the total mass density and derivatives - return Base::compute(ei, [&](localIndex const ip) - { - dTotalMassDens_dTemp += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; - dTotalMassDens_dT += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; - }); - } + dTotalMassDens_dTemp += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; + dTotalMassDens_dT += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; + } ); + } - protected: - // outputs - arrayView1d m_dTotalMassDens_dTemp; - }; +protected: + // outputs + arrayView1d< real64 > m_dTotalMassDens_dTemp; +}; - /** - * @class TotalMassDensityKernelFactory - */ - class TotalMassDensityKernelFactory +/** + * @class TotalMassDensityKernelFactory + */ +class TotalMassDensityKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp the number of fluid components + * @param[in] numPhase the number of fluid phases + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + MultiFluidBase const & fluid ) + { + if( numPhase == 2 ) { - public: - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComp the number of fluid components - * @param[in] numPhase the number of fluid phases - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - template - static void - createAndLaunch(integer const numComp, - integer const numPhase, - ObjectManagerBase &subRegion, - MultiFluidBase const &fluid) + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&]( auto NC ) { - if (numPhase == 2) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch(numComp, [&](auto NC) - { integer constexpr NUM_COMP = NC(); TotalMassDensityKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); - TotalMassDensityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); }); - } - else if (numPhase == 3) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch(numComp, [&](auto NC) - { - integer constexpr NUM_COMP = NC(); - TotalMassDensityKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); - TotalMassDensityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); }); - } - } - }; - - /******************************** ElementBasedAssemblyKernel ********************************/ - - /** - * @class ElementBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @brief Define the interface for the assembly kernel in charge of thermal accumulation and volume balance - */ - template - class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel + TotalMassDensityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) { - public: - using Base = compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel; - using Base::m_dCompFrac_dCompDens; - using Base::m_dofNumber; - using Base::m_dPhaseCompFrac; - using Base::m_dPhaseDens; - using Base::m_dPhaseVolFrac; - using Base::m_dPoro_dPres; - using Base::m_elemGhostRank; - using Base::m_localMatrix; - using Base::m_localRhs; - using Base::m_numPhases; - using Base::m_phaseCompFrac; - using Base::m_phaseCompFrac_n; - using Base::m_phaseDens; - using Base::m_phaseDens_n; - using Base::m_phaseVolFrac; - using Base::m_phaseVolFrac_n; - using Base::m_porosity; - using Base::m_porosity_n; - using Base::m_rankOffset; - using Base::m_volume; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - - /** - * @brief Constructor - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - ElementBasedAssemblyKernel(localIndex const numPhases, - globalIndex const rankOffset, - string const dofKey, - ElementSubRegionBase const &subRegion, - MultiFluidBase const &fluid, - CRSMatrixView const &localMatrix, - arrayView1d const &localRhs, - BitFlags const kernelFlags) - : Base(numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags), - m_phaseInternalEnergy_n(fluid.phaseInternalEnergy_n()), - m_phaseInternalEnergy(fluid.phaseInternalEnergy()), - m_dPhaseInternalEnergy(fluid.dPhaseInternalEnergy()) - { - } - - struct StackVariables : public Base::StackVariables - { - public: - GEOS_HOST_DEVICE - StackVariables() - : Base::StackVariables() - { - } - - using Base::StackVariables::dofIndices; - using Base::StackVariables::localJacobian; - using Base::StackVariables::localResidual; - using Base::StackVariables::localRow; - using Base::StackVariables::volume; - - - - }; - /** - * @brief Performs the setup phase for the kernel. - * @param[in] ei the element index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup(localIndex const ei, - StackVariables &stack) const + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&]( auto NC ) { - Base::setup(ei, stack); + integer constexpr NUM_COMP = NC(); + TotalMassDensityKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + TotalMassDensityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + } +}; - } +/******************************** ElementBasedAssemblyKernel ********************************/ - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeAccumulation(localIndex const ei, - StackVariables &stack) const - { - using Deriv = multifluid::DerivativeOffset; +/** + * @class ElementBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of thermal accumulation and volume balance + */ +template< localIndex NUM_COMP, localIndex NUM_DOF > +class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > +{ +public: + using Base = compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >; + using Base::m_dCompFrac_dCompDens; + using Base::m_dofNumber; + using Base::m_dPhaseCompFrac; + using Base::m_dPhaseDens; + using Base::m_dPhaseVolFrac; + using Base::m_dPoro_dPres; + using Base::m_elemGhostRank; + using Base::m_localMatrix; + using Base::m_localRhs; + using Base::m_numPhases; + using Base::m_phaseCompFrac; + using Base::m_phaseCompFrac_n; + using Base::m_phaseDens; + using Base::m_phaseDens_n; + using Base::m_phaseVolFrac; + using Base::m_phaseVolFrac_n; + using Base::m_porosity; + using Base::m_porosity_n; + using Base::m_rankOffset; + using Base::m_volume; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel( localIndex const numPhases, + globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) + : Base( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ), + m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n()), + m_phaseInternalEnergy( fluid.phaseInternalEnergy()), + m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy()) + {} + + struct StackVariables : public Base::StackVariables + { +public: + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + {} + using Base::StackVariables::eqnRowIndices; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localJacobian; + using Base::StackVariables::localResidual; + using Base::StackVariables::localRow; + using Base::StackVariables::volume; + + + + }; + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + } + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack ) const + { + using Deriv = multifluid::DerivativeOffset; - Base::computeAccumulation(ei, stack, [&](integer const ip, real64 const &phaseAmount, real64 const &phaseAmount_n, real64 const &dPhaseAmount_dP, real64 const(&dPhaseAmount_dC)[numComp]) - { + Base::computeAccumulation( ei, stack, [&]( integer const ip, real64 const & phaseAmount, real64 const & phaseAmount_n, real64 const & dPhaseAmount_dP, real64 const (&dPhaseAmount_dC)[numComp] ) + { // We are in the loop over phases, ip provides the current phase index. // We have to do two things: // 1- Assemble the derivatives of the component mass balance equations with respect to temperature @@ -294,25 +293,26 @@ namespace geos { stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount_dC[jc] + dPhaseInternalEnergy_dC[jc] * phaseAmount; - } }); - - } + } ); - /** - * @brief Compute the local volume balance contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeVolumeBalance(localIndex const ei, - StackVariables &stack) const - { - using Deriv = multifluid::DerivativeOffset; - Base::computeVolumeBalance(ei, stack, [&](real64 const &oneMinusPhaseVolFraction) - { + } + + /** + * @brief Compute the local volume balance contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeVolumeBalance( localIndex const ei, + StackVariables & stack ) const + { + using Deriv = multifluid::DerivativeOffset; + + Base::computeVolumeBalance( ei, stack, [&]( real64 const & oneMinusPhaseVolFraction ) + { GEOS_UNUSED_VAR( oneMinusPhaseVolFraction ); arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; @@ -320,68 +320,70 @@ namespace geos for( integer ip = 0; ip < m_numPhases; ++ip ) { stack.localJacobian[numEqn-2][numDof-1] -= dPhaseVolFrac[ip][Deriv::dT]; - } }); } + } ); + } - GEOS_HOST_DEVICE - void complete(localIndex const ei, - StackVariables &stack) const - { - // Step 1: assemble the component mass balance equations and volume balance equations - Base::complete(ei, stack); - - // Step 2: assemble the energy equation - m_localRhs[stack.localRow + numEqn - 1] += stack.localResidual[numEqn - 1]; - m_localMatrix.template addToRow(stack.localRow + numEqn - 1, - stack.dofIndices, - stack.localJacobian[numEqn - 1], - numDof); - } + GEOS_HOST_DEVICE + void complete( localIndex const ei, + StackVariables & stack ) const + { + // Step 1: assemble the component mass balance equations and volume balance equations + Base::complete( ei, stack ); + /* fix me tjb + // Step 2: assemble the energy equation + m_localRhs[stack.localRow + numEqn - 1] += stack.localResidual[numEqn - 1]; + m_localMatrix.template addToRow(stack.localRow + numEqn - 1, + stack.dofIndices, + stack.localJacobian[numEqn - 1], + numDof); + */ + } - protected: - /// View on derivative of porosity w.r.t temperature - arrayView2d const m_dPoro_dTemp; +protected: + /// View on derivative of porosity w.r.t temperature + arrayView2d< real64 const > const m_dPoro_dTemp; - /// Views on phase internal energy - arrayView3d m_phaseInternalEnergy_n; - arrayView3d m_phaseInternalEnergy; - arrayView4d m_dPhaseInternalEnergy; + /// Views on phase internal energy + arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy_n; + arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy; - }; +}; - /** - * @class ElementBasedAssemblyKernelFactory - */ - class ElementBasedAssemblyKernelFactory +/** + * @class ElementBasedAssemblyKernelFactory + */ +class ElementBasedAssemblyKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( localIndex const numComps, + localIndex const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { - public: - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] numComps the number of fluid components - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template - static void - createAndLaunch(localIndex const numComps, - localIndex const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - string const dofKey, - ElementSubRegionBase const &subRegion, - MultiFluidBase const &fluid, - CRSMatrixView const &localMatrix, - arrayView1d const &localRhs) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch(numComps, [&](auto NC) - { localIndex constexpr NUM_COMP = NC(); localIndex constexpr NUM_DOF = NC()+2; @@ -392,11 +394,471 @@ namespace geos ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > kernel( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); }); + launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); + } ); + } +}; +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NC, integer NUM_DOF > +class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, NUM_DOF > +{ +public: + + using Base = compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, NUM_DOF >; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using TAG = compositionalMultiphaseWellKernels::ElemTag; + + + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + FaceBasedAssemblyKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellControls const & wellControls, + ElementSubRegionBase const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + : Base( dt , rankOffset , subRegion.getReference< array1d< globalIndex > >( wellDofKey ) + , subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString()) + , subRegion.getField< fields::well::mixtureConnectionRate >() + , subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() + , localMatrix + , localRhs + , kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) + , wellControls.isProducer() + , wellControls.getInjectionStream() ) + { } + + + GEOS_HOST_DEVICE + inline + void + computeExit( real64 const & dt, + real64 const ( &compFlux )[NC], + real64 const ( &dCompFlux_dRate )[NC], + real64 const ( &dCompFlux_dPresUp )[NC], + real64 const ( &dCompFlux_dCompDensUp )[NC][NC], + real64 ( & oneSidedFlux )[NC], + real64 ( & oneSidedFluxJacobian_dRate )[NC][1], + real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ) const + { + for( integer ic = 0; ic < NC; ++ic ) + { + oneSidedFlux[ic] = -dt * compFlux[ic]; + + // derivative with respect to rate + oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; + + // derivative with respect to upstream pressure + oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; + + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; } - }; + } + } + + GEOS_HOST_DEVICE + inline + void + compute( real64 const & dt, + real64 const ( &compFlux )[NC], + real64 const ( &dCompFlux_dRate )[NC], + real64 const ( &dCompFlux_dPresUp )[NC], + real64 const ( &dCompFlux_dCompDensUp )[NC][NC], + real64 ( & localFlux )[2*NC], + real64 ( & localFluxJacobian_dRate )[2*NC][1], + real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ) const + { + // flux terms + for( integer ic = 0; ic < NC; ++ic ) + { + localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; + localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; + + // derivative with respect to rate + localFluxJacobian_dRate[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dRate[ic]; + localFluxJacobian_dRate[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dRate[ic]; + + // derivative with respect to upstream pressure + localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dPresUp[ic]; + localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dPresUp[ic]; + + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; + localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; + } + } + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iwelem, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + using namespace compositionalMultiphaseUtilities; + + // create local work arrays + real64 compFracUp[NC]{}; + real64 dCompFrac_dCompDensUp[NC][NC]{}; + + real64 compFlux[NC]{}; + real64 dCompFlux_dRate[NC]{}; + real64 dCompFlux_dPresUp[NC]{}; + real64 dCompFlux_dCompDensUp[NC][NC]{}; + + // Step 1) decide the upwind well element + + /* currentConnRate < 0 flow from iwelem to iwelemNext + * currentConnRate > 0 flow from iwelemNext to iwelem + * With this convention, currentConnRate < 0 at the last connection for a producer + * currentConnRate > 0 at the last connection for a injector + */ + + localIndex const iwelemNext = m_nextWellElemIndex[iwelem]; + real64 const currentConnRate = m_connRate[iwelem]; + localIndex iwelemUp = -1; + + if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + { + // we still need to define iwelemUp for Jacobian assembly + iwelemUp = iwelem; + + // just copy the injection stream into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_injection[ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFrac_dCompDensUp[ic][jc] = 0.0; + } + } + } + else + { + // first set iwelemUp to the upstream cell + if( ( iwelemNext < 0 && m_isProducer ) // exit connection, producer + || currentConnRate < 0 ) // not an exit connection, iwelem is upstream + { + iwelemUp = iwelem; + } + else // not an exit connection, iwelemNext is upstream + { + iwelemUp = iwelemNext; + } + + // copy the vars of iwelemUp into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_wellElemCompFrac[iwelemUp][ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFrac_dCompDensUp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + } + } + } + + // Step 2) compute upstream transport coefficient + + for( integer ic = 0; ic < NC; ++ic ) + { + compFlux[ic] = compFracUp[ic] * currentConnRate; + dCompFlux_dRate[ic] = compFracUp[ic]; + dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; + } + } + + globalIndex const offsetUp = m_wellElemDofNumber[iwelemUp]; + globalIndex const offsetCurrent = m_wellElemDofNumber[iwelem]; + + if( iwelemNext < 0 ) // exit connection + { + // for this case, we only need NC mass conservation equations + // so we do not use the arrays initialized before the loop + real64 oneSidedFlux[NC]{}; + real64 oneSidedFluxJacobian_dRate[NC][1]{}; + real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; + + computeExit ( m_dt, + compFlux, + dCompFlux_dRate, + dCompFlux_dPresUp, + dCompFlux_dCompDensUp, + oneSidedFlux, + oneSidedFluxJacobian_dRate, + oneSidedFluxJacobian_dPresCompUp ); + + + globalIndex oneSidedEqnRowIndices[NC]{}; + globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; + globalIndex oneSidedDofColIndices_dRate = 0; + + // jacobian indices + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + oneSidedEqnRowIndices[ic] = offsetUp + ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // in the dof ordering used in this class, there are 1 pressure dofs + // and NC compDens dofs before the rate dof in this block + localIndex const dRateColOffset = COFFSET::DCOMP + NC; + oneSidedDofColIndices_dRate = offsetCurrent + dRateColOffset; + + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + // dofs are the **upstream** pressure and component densities + oneSidedDofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; + } + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NC + 1]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); + } + + for( integer i = 0; i < NC; ++i ) + { + if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + &oneSidedDofColIndices_dRate, + oneSidedFluxJacobian_dRate[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + oneSidedDofColIndices_dPresCompUp, + oneSidedFluxJacobian_dPresCompUp[i], + NC+1 ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); + } + } + } + else // not an exit connection + { + real64 localFlux[2*NC]{}; + real64 localFluxJacobian_dRate[2*NC][1]{}; + real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; + + compute( m_dt, + compFlux, + dCompFlux_dRate, + dCompFlux_dPresUp, + dCompFlux_dCompDensUp, + localFlux, + localFluxJacobian_dRate, + localFluxJacobian_dPresCompUp ); + + + globalIndex eqnRowIndices[2*NC]{}; + globalIndex dofColIndices_dPresCompUp[NC+1]{}; + globalIndex dofColIndices_dRate = 0; + + globalIndex const offsetNext = m_wellElemDofNumber[iwelemNext]; + + // jacobian indices + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + eqnRowIndices[TAG::NEXT *NC+ic] = offsetNext + ROFFSET::MASSBAL + ic - m_rankOffset; + eqnRowIndices[TAG::CURRENT *NC+ic] = offsetCurrent + ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // in the dof ordering used in this class, there are 1 pressure dofs + // and NC compDens dofs before the rate dof in this block + localIndex const dRateColOffset = COFFSET::DCOMP + NC; + dofColIndices_dRate = offsetCurrent + dRateColOffset; + + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + // dofs are the **upstream** pressure and component densities + dofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; + } + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NC + 1]{}; + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); + } + + for( integer i = 0; i < 2*NC; ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], + &dofColIndices_dRate, + localFluxJacobian_dRate[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices_dPresCompUp, + localFluxJacobian_dPresCompUp[i], + NC+1 ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localFlux[i] ); + } + } + } + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + //typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + // kernelComponent.numPointsInFlux( iconn ) ); + + //kernelComponent.setup( iconn, stack ); + kernelComponent.computeFlux( ie ); + //kernelComponent.complete( iconn, stack ); + } ); + } + +protected: + /// Time step size + real64 const m_dt; + /// Rank offset for calculating row/col Jacobian indices + integer const m_rankOffset; + + /// Reference to the degree-of-freedom numbers + arrayView1d< globalIndex const > const m_wellElemDofNumber; + /// Next element index, needed since iterating over element nodes, not edges + arrayView1d< localIndex const > const m_nextWellElemIndex; + + /// Connection rate + arrayView1d< real64 const > const m_connRate; + + /// Element component fraction + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; + /// Element component fraction derivatives + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + /// Kernel option flag + integer const m_useTotalMassEquation; + + /// Well type + bool const m_isProducer; + + /// Injection stream composition + arrayView1d< real64 const > const m_injection; + + +}; + +/** + * @class FaceBasedAssemblyKernelFactory + */ +class FaceBasedAssemblyKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + real64 const dt, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const dofKey, + WellControls const & wellControls, + ElementSubRegionBase const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 2; + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + + + using kernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF >; + + + kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } +}; - }; // end namespace thermalCompositionalMultiphaseWellKernels +}; // end namespace thermalCompositionalMultiphaseWellKernels } // end namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 5a53ec5502f..c0316d34cb5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -32,66 +32,66 @@ namespace geos { - using namespace dataRepository; - using namespace constitutive; - - WellSolverBase::WellSolverBase(string const &name, - Group *const parent) - : SolverBase(name, parent), - m_numDofPerWellElement(0), - m_numDofPerResElement(0), - m_isThermal(false), - m_ratesOutputDir(joinPath(OutputBase::getOutputDirectory(), name + "_rates")) - { - this->getWrapper(viewKeyStruct::discretizationString()).setInputFlag(InputFlags::FALSE); - } +using namespace dataRepository; +using namespace constitutive; + +WellSolverBase::WellSolverBase( string const & name, + Group * const parent ) + : SolverBase( name, parent ), + m_numDofPerWellElement( 0 ), + m_numDofPerResElement( 0 ), + m_isThermal( false ), + m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" )) +{ + this->getWrapper< string >( viewKeyStruct::discretizationString()).setInputFlag( InputFlags::FALSE ); +} - Group *WellSolverBase::createChild(string const &childKey, string const &childName) - { - Group *rval = nullptr; +Group *WellSolverBase::createChild( string const & childKey, string const & childName ) +{ + Group *rval = nullptr; - if (childKey == keys::wellControls) - { - rval = ®isterGroup(childName); - } - else - { - SolverBase::createChild(childKey, childName); - } - return rval; + if( childKey == keys::wellControls ) + { + rval = ®isterGroup< WellControls >( childName ); } - - void WellSolverBase::expandObjectCatalogs() + else { - createChild(keys::wellControls, keys::wellControls); + SolverBase::createChild( childKey, childName ); } + return rval; +} - WellSolverBase::~WellSolverBase() = default; +void WellSolverBase::expandObjectCatalogs() +{ + createChild( keys::wellControls, keys::wellControls ); +} - void WellSolverBase::postProcessInput() - { - SolverBase::postProcessInput(); +WellSolverBase::~WellSolverBase() = default; + +void WellSolverBase::postProcessInput() +{ + SolverBase::postProcessInput(); - // create dir for rates output - if (getLogLevel() > 0) + // create dir for rates output + if( getLogLevel() > 0 ) + { + if( MpiWrapper::commRank() == 0 ) { - if (MpiWrapper::commRank() == 0) - { - makeDirsForPath(m_ratesOutputDir); - } - // wait till the dir is created by rank 0 - MPI_Barrier(MPI_COMM_WORLD); + makeDirsForPath( m_ratesOutputDir ); } + // wait till the dir is created by rank 0 + MPI_Barrier( MPI_COMM_WORLD ); } +} - void WellSolverBase::registerDataOnMesh(Group &meshBodies) - { - SolverBase::registerDataOnMesh(meshBodies); +void WellSolverBase::registerDataOnMesh( Group & meshBodies ) +{ + SolverBase::registerDataOnMesh( meshBodies ); - forDiscretizationOnMeshTargets(meshBodies, [&](string const &, - MeshLevel &meshLevel, - arrayView1d const ®ionNames) - { + forDiscretizationOnMeshTargets( meshBodies, [&]( string const &, + MeshLevel & meshLevel, + arrayView1d< string const > const & regionNames ) + { ElementRegionManager & elementRegionManager = meshLevel.getElemManager(); elementRegionManager.forElementSubRegions< WellElementSubRegion >( regionNames, @@ -108,23 +108,24 @@ namespace geos PerforationData * const perforationData = subRegion.getPerforationData(); perforationData->registerField< fields::well::gravityCoefficient >( getName() ); - } ); }); - } + } ); + } ); +} - void WellSolverBase::setConstitutiveNamesCallSuper(ElementSubRegionBase &subRegion) const - { - SolverBase::setConstitutiveNamesCallSuper(subRegion); - subRegion.registerWrapper(viewKeyStruct::fluidNamesString()).setPlotLevel(PlotLevel::NOPLOT).setRestartFlags(RestartFlags::NO_WRITE).setSizedFromParent(0); - } +void WellSolverBase::setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const +{ + SolverBase::setConstitutiveNamesCallSuper( subRegion ); + subRegion.registerWrapper< string >( viewKeyStruct::fluidNamesString()).setPlotLevel( PlotLevel::NOPLOT ).setRestartFlags( RestartFlags::NO_WRITE ).setSizedFromParent( 0 ); +} - void WellSolverBase::setupDofs(DomainPartition const &domain, - DofManager &dofManager) const +void WellSolverBase::setupDofs( DomainPartition const & domain, + DofManager & dofManager ) const +{ + map< std::pair< string, string >, array1d< string > > meshTargets; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const & meshBodyName, + MeshLevel const & meshLevel, + arrayView1d< string const > const & regionNames ) { - map, array1d> meshTargets; - forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &meshBodyName, - MeshLevel const &meshLevel, - arrayView1d const ®ionNames) - { array1d< string > regions; ElementRegionManager const & elementRegionManager = meshLevel.getElemManager(); elementRegionManager.forElementRegions< WellElementRegion >( regionNames, @@ -134,162 +135,320 @@ namespace geos regions.emplace_back( region.getName() ); } ); auto const key = std::make_pair( meshBodyName, meshLevel.getName()); - meshTargets[key] = std::move( regions ); }); - - dofManager.addField(wellElementDofName(), - FieldLocation::Elem, - numDofPerWellElement(), - meshTargets); - - dofManager.addCoupling(wellElementDofName(), - wellElementDofName(), - DofManager::Connector::Node); + meshTargets[key] = std::move( regions ); + } ); + + dofManager.addField( wellElementDofName(), + FieldLocation::Elem, + numDofPerWellElement(), + meshTargets ); + + dofManager.addCoupling( wellElementDofName(), + wellElementDofName(), + DofManager::Connector::Node ); +} + +void WellSolverBase::implicitStepSetup( real64 const & time_n, + real64 const & GEOS_UNUSED_PARAM( dt ), + DomainPartition & domain ) +{ + // Initialize the primary and secondary variables for the first time step + if( time_n <= 0.0 ) + { + initializeWells( domain ); } - - void WellSolverBase::implicitStepSetup(real64 const &time_n, - real64 const &GEOS_UNUSED_PARAM(dt), - DomainPartition &domain) +} + +void WellSolverBase::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + if( false && m_isThermal ) { - // Initialize the primary and secondary variables for the first time step - if (time_n <= 0.0) + integer const useTotalMassEquation = 1; + string const wellDofKey = dofManager.getKey( wellElementDofName()); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - initializeWells(domain); - } + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + string const dofKey = dofManager.getKey( CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString()); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numPhases = fluid.numFluidPhases(); + int numComponents = fluid.numFluidComponents(); + + thermalCompositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } ); + } ); } - - void WellSolverBase::assembleSystem(real64 const time, - real64 const dt, - DomainPartition &domain, - DofManager const &dofManager, - CRSMatrixView const &localMatrix, - arrayView1d const &localRhs) + else if( 0 ) { - GEOS_MARK_FUNCTION; - if (false && m_isThermal) + + integer const useTotalMassEquation = 1; + string const wellDofKey = dofManager.getKey( wellElementDofName()); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - integer const useTotalMassEquation = 1; - string const wellDofKey = dofManager.getKey(wellElementDofName()); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numPhases = fluid.numFluidPhases(); + int numComponents = fluid.numFluidComponents(); + + compositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } ); + } ); + // then assemble the pressure relations between well elements + assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); + + // then compute the perforation rates (later assembled by the coupled solver) + computePerforationRates( domain ); + + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + + } + else if( 1 ) { - mesh.getElemManager().forElementSubRegions( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) + integer const useTotalMassEquation = 1; + string const wellDofKey = dofManager.getKey( wellElementDofName()); + if ( 1 ) + { + + + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) { - string const dofKey = dofManager.getKey(CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString()); - string const &fluidName = subRegion.getReference(viewKeyStruct::fluidNamesString()); - - MultiFluidBase const &fluid = getConstitutiveModel(subRegion, fluidName); - int numComponents = fluid.numFluidPhases(); - int numPhases = fluid.numFluidComponents(); - - thermalCompositionalMultiphaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch>(numComponents, - numPhases, - dofManager.rankOffset(), - useTotalMassEquation, - wellDofKey, - subRegion, - fluid, - localMatrix, - localRhs); - }); - }); + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numPhases = fluid.numFluidPhases(); + int numComponents = fluid.numFluidComponents(); + if ( m_isThermal ) + { + + thermalCompositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + } ); + } ); } else { - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms(domain, dofManager, localMatrix, localRhs); - - // then assemble the flux terms in the mass balance equations - assembleFluxTerms(dt, domain, dofManager, localMatrix, localRhs); + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); - // then assemble the volume balance equations - assembleVolumeBalanceTerms(domain, dofManager, localMatrix, localRhs); + // then assemble the volume balance equations + assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + } + // then assemble the pressure relations between well elements + assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - // then assemble the pressure relations between well elements - assemblePressureRelations(time, dt, domain, dofManager, localMatrix, localRhs); + // then compute the perforation rates (later assembled by the coupled solver) + computePerforationRates( domain ); - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates(domain); + // then assemble the flux terms in the mass balance equations + // get a reference to the degree-of-freedom numbers + if ( 0 ) + { + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + } + else + { + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + WellControls const & well_controls = getWellControls( subRegion ); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numComponents = fluid.numFluidComponents(); + + compositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + localMatrix, + localRhs ); + } ); + } ); } - - // then apply a special treatment to the wells that are shut - shutDownWell(time, dt, domain, dofManager, localMatrix, localRhs); } - - void WellSolverBase::updateState(DomainPartition &domain) + else { + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); - forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &, - MeshLevel &mesh, - arrayView1d const ®ionNames) - { mesh.getElemManager().forElementSubRegions(regionNames, [&](localIndex const, - WellElementSubRegion &subRegion) - { updateSubRegionState(subRegion); }); }); + // then assemble the volume balance equations + assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + + // then assemble the pressure relations between well elements + assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); + + // then compute the perforation rates (later assembled by the coupled solver) + computePerforationRates( domain ); + + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); } - void WellSolverBase::initializePostInitialConditionsPreSubGroups() + // then apply a special treatment to the wells that are shut + shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); +} + +void WellSolverBase::updateState( DomainPartition & domain ) +{ + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - SolverBase::initializePostInitialConditionsPreSubGroups(); + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) + { updateSubRegionState( subRegion ); } ); + } ); +} - DomainPartition &domain = this->getGroupByPath("/Problem/domain"); +void WellSolverBase::initializePostInitialConditionsPreSubGroups() +{ + SolverBase::initializePostInitialConditionsPreSubGroups(); - // make sure that nextWellElementIndex is up-to-date (will be used in well initialization and assembly) - forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &, - MeshLevel &mesh, - arrayView1d const ®ionNames) - { mesh.getElemManager().forElementSubRegions(regionNames, [&](localIndex const, - WellElementSubRegion &subRegion) - { subRegion.reconstructLocalConnectivity(); }); }); + DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); - // Precompute solver-specific constant data (e.g. gravity-coefficient) - precomputeData(domain); - } + // make sure that nextWellElementIndex is up-to-date (will be used in well initialization and assembly) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) + { subRegion.reconstructLocalConnectivity(); } ); + } ); - void WellSolverBase::precomputeData(DomainPartition &domain) + // Precompute solver-specific constant data (e.g. gravity-coefficient) + precomputeData( domain ); +} + +void WellSolverBase::precomputeData( DomainPartition & domain ) +{ + R1Tensor const gravVector = gravityVector(); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - R1Tensor const gravVector = gravityVector(); - forDiscretizationOnMeshTargets(domain.getMeshBodies(), [&](string const &, - MeshLevel &mesh, - arrayView1d const ®ionNames) - { mesh.getElemManager().forElementSubRegions(regionNames, [&](localIndex const, - WellElementSubRegion &subRegion) - { - PerforationData &perforationData = *subRegion.getPerforationData(); - WellControls &wellControls = getWellControls(subRegion); - real64 const refElev = wellControls.getReferenceElevation(); - - arrayView2d const wellElemLocation = subRegion.getElementCenter(); - arrayView1d const wellElemGravCoef = subRegion.getField(); - - arrayView2d const perfLocation = perforationData.getField(); - arrayView1d const perfGravCoef = perforationData.getField(); - - forAll(perforationData.size(), [=](localIndex const iperf) - { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + PerforationData & perforationData = *subRegion.getPerforationData(); + WellControls & wellControls = getWellControls( subRegion ); + real64 const refElev = wellControls.getReferenceElevation(); + + arrayView2d< real64 const > const wellElemLocation = subRegion.getElementCenter(); + arrayView1d< real64 > const wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); + + arrayView2d< real64 const > const perfLocation = perforationData.getField< fields::perforation::location >(); + arrayView1d< real64 > const perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >(); + + forAll< serialPolicy >( perforationData.size(), [=]( localIndex const iperf ) + { // precompute the depth of the perforations - perfGravCoef[iperf] = LvArray::tensorOps::AiBi< 3 >( perfLocation[iperf], gravVector ); }); + perfGravCoef[iperf] = LvArray::tensorOps::AiBi< 3 >( perfLocation[iperf], gravVector ); + } ); - forAll(subRegion.size(), [=](localIndex const iwelem) - { + forAll< serialPolicy >( subRegion.size(), [=]( localIndex const iwelem ) + { // precompute the depth of the well elements - wellElemGravCoef[iwelem] = LvArray::tensorOps::AiBi< 3 >( wellElemLocation[iwelem], gravVector ); }); + wellElemGravCoef[iwelem] = LvArray::tensorOps::AiBi< 3 >( wellElemLocation[iwelem], gravVector ); + } ); - // set the reference well element where the BHP control is applied - wellControls.setReferenceGravityCoef(refElev * gravVector[2]); }); }); - } + // set the reference well element where the BHP control is applied + wellControls.setReferenceGravityCoef( refElev * gravVector[2] ); + } ); + } ); +} - WellControls &WellSolverBase::getWellControls(WellElementSubRegion const &subRegion) - { - return this->getGroup(subRegion.getWellControlsName()); - } +WellControls & WellSolverBase::getWellControls( WellElementSubRegion const & subRegion ) +{ + return this->getGroup< WellControls >( subRegion.getWellControlsName()); +} - WellControls const &WellSolverBase::getWellControls(WellElementSubRegion const &subRegion) const - { - return this->getGroup(subRegion.getWellControlsName()); - } +WellControls const & WellSolverBase::getWellControls( WellElementSubRegion const & subRegion ) const +{ + return this->getGroup< WellControls >( subRegion.getWellControlsName()); +} } // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 91eb5d138bf..3724a1e2e81 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -317,7 +317,7 @@ class WellSolverBase : public SolverBase /// the number of Degrees of Freedom per reservoir element integer m_numDofPerResElement; - /// flag indicating whether thermal formulation is used + /// flag indicating whether thermal formulation is used integer m_isThermal; string const m_ratesOutputDir; From aee32bc480cde8badb72e9aa063f50fde19d0ca2 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:29:52 -0700 Subject: [PATCH 11/71] thermal devs- 1) energy eqn for perf in/out flows, 2) reservoir well coupling 3) residualnomr calcs, 4) some isothermal , 5) refactoring 6) next focus solution updating/scaling --- .../common/KernelLaunchSelectors.hpp | 170 +++ .../constitutive/fluid/multifluid/Layouts.hpp | 24 +- .../fluid/multifluid/MultiFluidBase.hpp | 2 +- .../fluid/singlefluid/SingleFluidBase.hpp | 8 + .../mesh/utilities/ComputationalGeometry.hpp | 2 +- ...rmalCompositionalMultiphaseBaseKernels.hpp | 56 +- .../wells/CompositionalMultiphaseWell.cpp | 426 +++++-- .../wells/CompositionalMultiphaseWell.hpp | 25 +- .../CompositionalMultiphaseWellFields.hpp | 1 + .../CompositionalMultiphaseWellKernels.cpp | 142 +-- .../CompositionalMultiphaseWellKernels.hpp | 881 +++++++++++++- .../wells/PerforationFluxKernels.hpp | 1059 +++++++++++++++++ .../fluidFlow/wells/SinglePhaseWell.cpp | 107 +- .../fluidFlow/wells/SinglePhaseWell.hpp | 2 + .../wells/SinglePhaseWellKernels.hpp | 298 +++++ ...rmalCompositionalMultiphaseWellKernels.hpp | 821 +++++++------ .../wells/ThermalSinglePhaseWellKernels.hpp | 247 ++++ .../wells/WellElementKernelUtilities.hpp | 283 +++++ .../fluidFlow/wells/WellFields.hpp | 59 + .../fluidFlow/wells/WellSolverBase.cpp | 28 +- .../fluidFlow/wells/WellSolverBase.hpp | 12 +- .../fluidFlow/wells/WellTags.hpp | 110 ++ ...mpositionalMultiphaseReservoirAndWells.cpp | 90 +- .../CoupledReservoirAndWellKernels.hpp | 604 ++++++++++ .../SinglePhaseReservoirAndWells.cpp | 13 +- 25 files changed, 4826 insertions(+), 644 deletions(-) create mode 100644 src/coreComponents/common/KernelLaunchSelectors.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/wells/WellTags.hpp create mode 100644 src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp diff --git a/src/coreComponents/common/KernelLaunchSelectors.hpp b/src/coreComponents/common/KernelLaunchSelectors.hpp new file mode 100644 index 00000000000..7b7ca2483e3 --- /dev/null +++ b/src/coreComponents/common/KernelLaunchSelectors.hpp @@ -0,0 +1,170 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file KernelLaunchSelectors.hpp + */ + +#ifndef GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP +#define GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP + +#include "common/Logger.hpp" + +namespace geos +{ +namespace internal { + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorThermalSwitch( T value, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorThermalSwitch: type should be integral" ); + + switch( value ) + { + case 0: + { lambda( std::integral_constant< T, 0 >() ); return; } + case 1: + { lambda( std::integral_constant< T, 1 >() ); return; } + + default: + { GEOS_ERROR( "Unsupported thermal state: " << value ); } + } +} + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorCompThermSwitch( T value, bool const isThermal, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); + + //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); + if( isThermal ) + { + switch( value ) + { + case 1: + { + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 1 >() ); return; + } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 1 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 1 >()); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } + } + else + { + switch( value ) + { + case 1: + { + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 0 >() ); return; + } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 0 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 0 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 0 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 0 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } + } +} + + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); + + //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); + if ( n_phase == 1 ) + { + switch( value ) + { + case 1: + { + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 1 >() ); return; + } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 1 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 1 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } + } + else if ( n_phase == 2 ) + { + switch( value ) + { + case 1: + { + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 2 >() ); return; + } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 2 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 2 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 2 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 2 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } + + } + else if ( n_phase == 3 ) + { + switch( value ) + { + case 1: + { + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 3 >() ); return; + } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 3 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 3 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 3 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 3 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } + } + else + { + { GEOS_ERROR( "Unsupported number of phases: " << n_phase ); } + } +} +} // end namspace internal +} // end namespace geos + + +#endif // GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP diff --git a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp index c626ec6b20d..6e80a4252d8 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp @@ -29,6 +29,18 @@ namespace geos { namespace constitutive { + +namespace singlefluid +{ +struct DerivativeOffset +{ + /// index of derivative wrt pressure + static integer constexpr dP = 0; + /// index of derivative wrt temperature + static integer constexpr dT = 1; + +}; +} namespace multifluid { @@ -45,11 +57,11 @@ struct DerivativeOffset }; /// indices of pressure, temperature, and composition derivatives -template < integer NC , integer IS_THERMAL> -struct DerivativeOffsetC{}; +template< integer NC, integer IS_THERMAL > +struct DerivativeOffsetC {}; -template < integer NC > -struct DerivativeOffsetC +template< integer NC > +struct DerivativeOffsetC< NC, 1 > { /// index of derivative wrt pressure static integer constexpr dP = 0; @@ -60,8 +72,8 @@ struct DerivativeOffsetC /// number of derivatives static integer constexpr nDer = NC + 2; }; -template < integer NC > -struct DerivativeOffsetC +template< integer NC > +struct DerivativeOffsetC< NC, 0 > { /// index of derivative wrt pressure static integer constexpr dP = 0; diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp index a221fa6ed0b..97926d5fc26 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp @@ -1059,7 +1059,7 @@ MultiFluidBase::KernelWrapper:: real64 const densInv = 1.0 / phaseMassDens.value[ip]; real64 const densInvSquared = densInv * densInv; phaseInternalEnergy.value[ip] = phaseEnthalpy.value[ip] - pressure * densInv; - for( integer idof = 0; idof < numComp; ++idof ) + for( integer idof = 0; idof < numComp+2; ++idof ) { phaseInternalEnergy.derivs[ip][idof] = phaseEnthalpy.derivs[ip][idof] + pressure * phaseMassDens.derivs[ip][idof] * densInvSquared; } diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp index 2f04795b81c..b3be95bd5f9 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp @@ -275,6 +275,14 @@ class SingleFluidBase : public ConstitutiveBase virtual real64 defaultDensity() const = 0; virtual real64 defaultViscosity() const = 0; +/** + * @brief Get the thermal flag. + * @return boolean value indicating whether the model can be used to assemble the energy balance equation or not + * @detail if isThermal is true, the constitutive model compute the enthalpy and internal energy of the phase. + * This can be used to check the compatibility of the constitutive model with the solver + */ + virtual bool isThermal() const { return false; } + protected: virtual void postProcessInput() override; diff --git a/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp b/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp index d90df153066..4b4383f6848 100644 --- a/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp +++ b/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp @@ -422,7 +422,7 @@ void getBoundingBox( localIndex const elemIndex, LvArray::NumericLimits< real64 >::max }; // boxDims is used to hold the max coordinates. - LvArray::tensorOps::fill< 3 >( boxDims, LvArray::NumericLimits< real64 >::min ); + LvArray::tensorOps::fill< 3 >( boxDims, LvArray::NumericLimits< real64 >::lowest ); // loop over all the vertices of the element to get the min and max coords for( localIndex a = 0; a < pointIndices.size( 1 ); ++a ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp index b363ab08528..a163ef23a32 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp @@ -23,6 +23,7 @@ #include "common/DataLayouts.hpp" #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" +#include "common/KernelLaunchSelectors.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "functions/TableFunction.hpp" @@ -37,6 +38,7 @@ namespace geos { + namespace isothermalCompositionalMultiphaseBaseKernels { @@ -114,51 +116,7 @@ class PropertyKernelBase namespace internal { -template< typename T, typename LAMBDA > -void kernelLaunchSelectorCompThermSwitch( T value , bool const isThermal , LAMBDA && lambda ) -{ - static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); - - //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); - if ( isThermal ) - { - switch( value ) - { - case 1: - { - lambda( std::integral_constant< T, 1 >() , std::integral_constant< T, 1 >() ); return; } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >() , std::integral_constant< T, 1 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >() ,std::integral_constant< T, 1 >()); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } - } - } - else - { - switch( value ) - { - case 1: - { - lambda( std::integral_constant< T, 1 >() , std::integral_constant< T, 0 >() ); return; } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 0 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >() , std::integral_constant< T, 0 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 0 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >() ,std::integral_constant< T, 0 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } - } - } -} + template< typename T, typename LAMBDA > void kernelLaunchSelectorCompSwitch( T value, LAMBDA && lambda ) @@ -2465,9 +2423,9 @@ struct HydrostaticPressureKernel template< typename KERNELWRAPPER, typename ... ARGS > -void KernelLaunchSelectorCompTherm( integer const numComp, bool const isThermal , ARGS && ... args ) +void KernelLaunchSelectorCompTherm( integer const numComp, bool const isThermal, ARGS && ... args ) { - internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal , [&] ( auto NC , auto ISTHERMAL ) + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { KERNELWRAPPER::template launch< NC(), ISTHERMAL() >( std::forward< ARGS >( args )... ); } ); @@ -2507,10 +2465,10 @@ void KernelLaunchSelector2( integer const numComp, integer const numPhase, ARGS } template< typename KERNELWRAPPER, typename ... ARGS > -void KernelLaunchSelector_NC_NP_THERM( integer const numComp, integer const numPhase ,integer const isThermal, ARGS && ... args ) +void KernelLaunchSelector_NC_NP_THERM( integer const numComp, integer const numPhase, integer const isThermal, ARGS && ... args ) { // Ideally this would be inside the dispatch, but it breaks on Summit with GCC 9.1.0 and CUDA 11.0.3. - if ( isThermal ) + if( isThermal ) { if( numPhase == 2 ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index fb6922673f3..c78711b525d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -34,15 +34,19 @@ #include "mesh/PerforationFields.hpp" #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" +#include "physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp" #include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" #include "physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" + #include "physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/fluidFlow/wells/WellFields.hpp" + #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" #endif @@ -58,9 +62,7 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, Group * const parent ) : WellSolverBase( name, parent ), - m_numPhases( 0 ), - m_numComponents( 0 ), - m_useMass( false ), + m_useMass( false ), m_useTotalMassEquation( 1 ), m_maxCompFracChange( 1.0 ), m_maxRelativePresChange( 0.2 ), @@ -69,6 +71,8 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, m_allowCompDensChopping( 1 ), m_targetPhaseIndex( -1 ) { + + this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useMass ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). @@ -146,11 +150,10 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) MultiFluidBase const & fluid0 = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName ); m_numPhases = fluid0.numFluidPhases(); m_numComponents = fluid0.numFluidComponents(); - m_isThermal = fluid0.isThermal(); - } - m_numDofPerWellElement = m_isThermal ? m_numComponents + 3 : m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate + + } + m_numDofPerWellElement = isThermal() ? m_numComponents + 3 : m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate + // temp if thermal - m_numDofPerResElement = m_isThermal ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure + NC compositions + temp if thermal + m_numDofPerResElement = isThermal() ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure + NC compositions + temp if thermal // loop over the wells forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, @@ -222,7 +225,13 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) perforationData.registerField< fields::well::compPerforationRate >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); perforationData.registerField< fields::well::dCompPerforationRate >( getName() ). - reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); + reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); + if( fluid.isThermal() ) + { + perforationData.registerField< fields::well::energyPerforationFlux >( getName() ); + perforationData.registerField< fields::well::dEnergyPerforationFlux >( getName() ). + reference().resizeDimension< 1, 2 >( 2, m_numComponents+2 ); + } // tjb - remove perforationData.registerField< fields::well::dCompPerforationRate_dPres >( getName() ). reference().resizeDimension< 1, 2 >( 2, m_numComponents ); @@ -635,11 +644,11 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); arrayView1d< real64 > const & dCurrentBHP_dCompDens = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dCompDensString() ); - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal , [&] ( auto NC , auto ISTHERMAL ) + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { - integer constexpr NUM_COMP = NC(); + //integer constexpr NUM_COMP = NC(); integer constexpr IS_THERMAL = ISTHERMAL(); - +GEOS_UNUSED_VAR( NC ); // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [&numComp, pres, @@ -669,7 +678,7 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & dCurrentBHP[Deriv::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef; } } ); - }); + } ); if( logLevel >= 2 ) { @@ -755,11 +764,11 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal , [&] ( auto NC , auto ISTHERMAL ) + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { integer constexpr NUM_COMP = NC(); integer constexpr IS_THERMAL = ISTHERMAL(); - using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac; + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NUM_COMP, IS_THERMAL >; // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [&numComp, &numPhase, @@ -918,7 +927,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg } } } ); - } ) ; + } ); } ); } @@ -997,7 +1006,133 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & fluid ); } +void CompositionalMultiphaseWell::assembleSystem1( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + integer const useTotalMassEquation = 1; + string const wellDofKey = dofManager.getKey( wellElementDofName()); + if( 0 ) + { + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numPhases = fluid.numFluidPhases(); + int numComponents = fluid.numFluidComponents(); + if( isThermal() ) + { + + thermalCompositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + } ); + } ); + } + else + { + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); + + // then assemble the volume balance equations + assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + } + // then assemble the pressure relations between well elements + assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); + // then compute the perforation rates (later assembled by the coupled solver) + computePerforationRates( domain ); + + // then assemble the flux terms in the mass balance equations + // get a reference to the degree-of-freedom numbers + if( 1 ) + { + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + } + else + { + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + WellControls const & well_controls = getWellControls( subRegion ); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numComponents = fluid.numFluidComponents(); + if( isThermal() ) + { + thermalCompositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + localMatrix, + localRhs ); + } + } ); + } ); + } + + +} void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update properties @@ -1186,6 +1321,17 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, } void CompositionalMultiphaseWell::assembleAccumulationTerms( DomainPartition const & domain, +DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + + +} + + +void CompositionalMultiphaseWell::assembleVolumeBalanceTerms( DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -1205,10 +1351,8 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( DomainPartition con [&]( localIndex const, WellElementSubRegion const & subRegion ) { - // get the degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey ); arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); // get the properties on the well element @@ -1217,42 +1361,19 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( DomainPartition con arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac = subRegion.getField< fields::well::dPhaseVolumeFraction >(); - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = - subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); - - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n = - subRegion.getField< fields::well::phaseVolumeFraction_n >(); - - arrayView1d< real64 const > const & wellElemVolume = subRegion.getElementVolume(); - - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens = fluid.dPhaseDensity(); - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac = fluid.phaseCompFraction(); - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac = fluid.dPhaseCompFraction(); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n = fluid.phaseDensity_n(); - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n = fluid.phaseCompFraction_n(); + arrayView1d< real64 const > const & wellElemVolume = + subRegion.getReference< array1d< real64 > >( ElementSubRegionBase::viewKeyStruct::elementVolumeString() ); isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< AccumulationKernel >( numFluidComponents(), + KernelLaunchSelector1< VolumeBalanceKernel >( numFluidComponents(), subRegion.size(), numFluidPhases(), dofManager.rankOffset(), - m_useTotalMassEquation, - wellElemDofNumber, + wellElemDofNumber, wellElemGhostRank, - wellElemVolume, - wellElemPhaseVolFrac, + wellElemPhaseVolFrac, dWellElemPhaseVolFrac, - dWellElemCompFrac_dCompDens, - wellElemPhaseDens, - dWellElemPhaseDens, - wellElemPhaseCompFrac, - dWellElemPhaseCompFrac, - wellElemPhaseVolFrac_n, - wellElemPhaseDens_n, - wellElemPhaseCompFrac_n, + wellElemVolume, localMatrix, localRhs ); } ); @@ -1260,13 +1381,28 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( DomainPartition con } -void CompositionalMultiphaseWell::assembleVolumeBalanceTerms( DomainPartition const & domain, +real64 +CompositionalMultiphaseWell::calculateResidualNorm1( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) + arrayView1d< real64 const > const & localRhs ) { GEOS_MARK_FUNCTION; +integer numNorm = 1; // mass balance + array1d< real64 > localResidualNorm; + array1d< real64 > localResidualNormalizer; + + if( isThermal() ) + { + numNorm = 2; // mass balance and energy balance + } + localResidualNorm.resize( numNorm ); + localResidualNormalizer.resize( numNorm ); + + + globalIndex const rankOffset = dofManager.rankOffset(); string const wellDofKey = dofManager.getKey( wellElementDofName() ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -1274,42 +1410,106 @@ void CompositionalMultiphaseWell::assembleVolumeBalanceTerms( DomainPartition co arrayView1d< string const > const & regionNames ) { + ElementRegionManager const & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion const & subRegion ) { - // get the degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); + - // get the properties on the well element - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac = - subRegion.getField< fields::well::phaseVolumeFraction >(); - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac = - subRegion.getField< fields::well::dPhaseVolumeFraction >(); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - arrayView1d< real64 const > const & wellElemVolume = - subRegion.getReference< array1d< real64 > >( ElementSubRegionBase::viewKeyStruct::elementVolumeString() ); + WellControls const & wellControls = getWellControls( subRegion ); - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< VolumeBalanceKernel >( numFluidComponents(), - subRegion.size(), - numFluidPhases(), - dofManager.rankOffset(), - wellElemDofNumber, - wellElemGhostRank, - wellElemPhaseVolFrac, - dWellElemPhaseVolFrac, - wellElemVolume, - localMatrix, - localRhs ); + // step 1: compute the norm in the subRegion + + if( isThermal() ) + { + real64 subRegionResidualNorm[2]{}; + + thermalCompositionalMultiphaseWellKernels::ResidualNormKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_targetPhaseIndex, + rankOffset, + wellDofKey, + localRhs, + subRegion, + fluid, + wellControls, + time_n + dt, + dt, + m_nonlinearSolverParameters.m_minNormalizer, + subRegionResidualNorm ); + // step 2: reduction across meshBodies/regions/subRegions + + for( integer i=0; i localResidualNorm[i] ) + { + localResidualNorm[i] = subRegionResidualNorm[i]; + } + } + + } + else + { + real64 subRegionResidualNorm[1]{}; + ResidualNormKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + numDofPerWellElement(), + m_targetPhaseIndex, + rankOffset, + wellDofKey, + localRhs, + subRegion, + fluid, + wellControls, + time_n + dt, + dt, + m_nonlinearSolverParameters.m_minNormalizer, + subRegionResidualNorm ); + + + + // step 2: reduction across meshBodies/regions/subRegions + + if( subRegionResidualNorm[0] > localResidualNorm[0] ) + { + localResidualNorm[0] = subRegionResidualNorm[0]; + } + } } ); } ); -} + + // step 3: second reduction across MPI ranks + real64 resNorm=localResidualNorm[0]; + if( isThermal() ) + { + real64 globalResidualNorm[2]{}; + globalResidualNorm[0] = MpiWrapper::max( localResidualNorm[0] ); + globalResidualNorm[1] = MpiWrapper::max( localResidualNorm[1] ); + resNorm=sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] ); + if( getLogLevel() >= 1 && logger::internal::rank == 0 ) + { + std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} ) ( Renergy ) = ( {:4.2e} )", + coupledSolverAttributePrefix(), globalResidualNorm[0], globalResidualNorm[1] ); + } + } + else + { + resNorm= MpiWrapper::max( resNorm ); + if( getLogLevel() >= 1 && logger::internal::rank == 0 ) + { + std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} )", coupledSolverAttributePrefix(), resNorm ); + } + } + return resNorm; +} real64 CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, real64 const & dt, @@ -1380,7 +1580,6 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, } return residualNorm; } - real64 CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, DofManager const & dofManager, @@ -1467,18 +1666,16 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom { GEOS_MARK_FUNCTION; - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) { // TODO: change the way we access the flowSolver here CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); - PerforationKernel::CompFlowAccessors resCompFlowAccessors( mesh.getElemManager(), flowSolver.getName() ); - PerforationKernel::MultiFluidAccessors resMultiFluidAccessors( mesh.getElemManager(), flowSolver.getName() ); - PerforationKernel::RelPermAccessors resRelPermAccessors( mesh.getElemManager(), flowSolver.getName() ); + ElementRegionManager & elemManager = mesh.getElemManager(); - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) { @@ -1490,6 +1687,40 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom bool isThermal = fluid.isThermal(); PerforationData * const perforationData = subRegion.getPerforationData(); +if( 1 ) + { + if( isThermal ) + { + thermalPerforationFluxKernels:: + PerforationFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + flowSolver.getName(), + perforationData, + subRegion, + fluid, + elemManager, + disableReservoirToWellFlow ); + } + else + { + isothermalPerforationFluxKernels:: + PerforationFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_numComponents, + m_numPhases, + flowSolver.getName(), + perforationData, + subRegion, + elemManager, + disableReservoirToWellFlow ); + } + + } + else + { + PerforationKernel::CompFlowAccessors resCompFlowAccessors( elemManager, flowSolver.getName() ); + PerforationKernel::MultiFluidAccessors resMultiFluidAccessors( elemManager, flowSolver.getName() ); + PerforationKernel::RelPermAccessors resRelPermAccessors( elemManager, flowSolver.getName() ); // get depth arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); @@ -1578,8 +1809,10 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom dCompPerfRate, dCompPerfRate_dPres, dCompPerfRate_dComp ); +} } ); + } ); } @@ -1592,26 +1825,44 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager, real64 const dt, DomainPartition & domain ) { + + DofManager::CompMask pressureMask( m_numDofPerWellElement, 0, 1 ); + DofManager::CompMask componentMask( m_numDofPerWellElement, 1, numFluidComponents()+1 ); + DofManager::CompMask connRateMask( m_numDofPerWellElement, numFluidComponents()+1, numFluidComponents()+2 ); GEOS_UNUSED_VAR( dt ); // update all the fields using the global damping coefficients dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::pressure::key(), scalingFactor, - { m_numDofPerWellElement, 0, 1 } ); + pressureMask ); + //{ m_numDofPerWellElement, 0, 1 } ); dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::globalCompDensity::key(), scalingFactor, - { m_numDofPerWellElement, 1, m_numDofPerWellElement - 1 } ); + componentMask ); + //{ m_numDofPerWellElement, 1, m_numDofPerWellElement - 1 } ); dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::mixtureConnectionRate::key(), scalingFactor, - { m_numDofPerWellElement, m_numDofPerWellElement - 1, m_numDofPerWellElement } ); + connRateMask ); + //{ m_numDofPerWellElement, m_numDofPerWellElement - 1, m_numDofPerWellElement } ); +if( isThermal() ) + { + DofManager::CompMask temperatureMask( m_numDofPerWellElement, numFluidComponents()+2, numFluidComponents()+3 ); + + dofManager.addVectorToField( localSolution, + wellElementDofName(), + fields::well::temperature::key(), + scalingFactor, + temperatureMask ); + + } // if component density chopping is allowed, some component densities may be negative after the update // these negative component densities are set to zero in this function if( m_allowCompDensChopping ) @@ -1768,7 +2019,8 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time bool controlHasSwitched = false; isothermalCompositionalMultiphaseBaseKernels:: KernelLaunchSelectorCompTherm< PressureRelationKernel >( numFluidComponents(), isThermal, - //isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1< PressureRelationKernel >( numFluidComponents(), + //isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1< + // PressureRelationKernel >( numFluidComponents(), subRegion.size(), dofManager.rankOffset(), subRegion.isLocallyOwned(), @@ -1776,7 +2028,7 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time isThermal, m_targetPhaseIndex, wellControls, - time_n + dt, // controls evaluated with BHP/rate of the end of step + time_n + dt, // controls evaluated with BHP/rate of the end of step wellElemDofNumber, wellElemGravCoef, nextWellElemIndex, @@ -1884,7 +2136,7 @@ void CompositionalMultiphaseWell::shutDownWell( real64 const time_n, rankOffset, localMatrix, rhsValue, - pres[ei], // freeze the current pressure value + pres[ei], // freeze the current pressure value pres[ei] ); localRhs[localRow] = rhsValue; @@ -1895,7 +2147,7 @@ void CompositionalMultiphaseWell::shutDownWell( real64 const time_n, rankOffset, localMatrix, rhsValue, - compDens[ei][ic], // freeze the current component density values + compDens[ei][ic], // freeze the current component density values compDens[ei][ic] ); localRhs[localRow + ic + 1] = rhsValue; } @@ -1905,7 +2157,7 @@ void CompositionalMultiphaseWell::shutDownWell( real64 const time_n, rankOffset, localMatrix, rhsValue, - connRate[ei], // freeze the current pressure value + connRate[ei], // freeze the current pressure value connRate[ei] ); localRhs[localRow + numComp + 1] = rhsValue; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 85c40951350..dac396dca3d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -92,6 +92,14 @@ class CompositionalMultiphaseWell : public WellSolverBase /**@{*/ + virtual real64 + calculateResidualNorm1( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ); + + virtual real64 calculateResidualNorm( real64 const & time_n, real64 const & dt, @@ -192,6 +200,12 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual localIndex numFluidPhases() const override { return m_numPhases; } +virtual void assembleSystem1( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); /** * @brief assembles the flux terms for all connections between well elements * @param time_n previous time value @@ -377,12 +391,8 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override; - /// the max number of fluid phases - integer m_numPhases; - - /// the number of fluid components - integer m_numComponents; - + + /// flag indicating whether mass or molar formulation should be used integer m_useMass; @@ -410,8 +420,7 @@ class CompositionalMultiphaseWell : public WellSolverBase /// index of the target phase, used to impose the phase rate constraint localIndex m_targetPhaseIndex; - /// name of the fluid constitutive model used as a reference for component/phase description - string m_referenceFluidModelName; + }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp index f4279a195f9..6e1bae9b22e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp @@ -211,6 +211,7 @@ DECLARE_FIELD( globalCompDensityScalingFactor, NO_WRITE, "Scaling factors for global component densities" ); + } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index 6fbfdd57c67..9e44861239f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -119,7 +119,7 @@ ControlEquationHelper:: } } -template< integer NC , integer IS_THERMAL > +template< integer NC, integer IS_THERMAL > GEOS_HOST_DEVICE inline void @@ -152,7 +152,7 @@ ControlEquationHelper:: { //using ROFFSETC = compositionalMultiphaseWellKernels::RowOffsetComplete; - using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac; + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; using Deriv = multifluid::DerivativeOffset; //using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; //using COFFSET = compositionalMultiphaseWellKernels::ColOffset; @@ -265,10 +265,10 @@ ControlEquationHelper:: dControlEqn_dComp, NC ); // tjb- remove when safe and modify local matrix updates - assert(fabs( dControlEqn[COFFSET_WJ::dP] -dControlEqn_dPres) < FLT_EPSILON); - assert(fabs( dControlEqn[COFFSET_WJ::dQ] - dControlEqn_dRate ) < FLT_EPSILON); - for( integer ic=0; ic +template< integer NC, integer IS_THERMAL > GEOS_HOST_DEVICE void PressureRelationKernel:: @@ -618,6 +619,12 @@ PressureRelationKernel:: real64 & localPresRel, real64 ( & localPresRelJacobian )[2*(NC+1 + IS_THERMAL)] ) { +GEOS_UNUSED_VAR( dTotalMassDens_dPres ); + + GEOS_UNUSED_VAR( dTotalMassDens_dCompDens ); + GEOS_UNUSED_VAR( dTotalMassDens_dPresNext ); + GEOS_UNUSED_VAR( dTotalMassDens_dCompDensNext ); + // local working variables and arrays real64 dAvgMassDens_dCompCurrent[NC]{}; real64 dAvgMassDens_dCompNext[NC]{}; @@ -660,10 +667,10 @@ PressureRelationKernel:: } } -template< integer NC , integer IS_THERMAL > +template< integer NC, integer IS_THERMAL > void PressureRelationKernel:: - launch( localIndex const size, + launch( localIndex const size, globalIndex const rankOffset, bool const isLocallyOwned, localIndex const iwelemControl, @@ -683,7 +690,8 @@ PressureRelationKernel:: CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac; + GEOS_UNUSED_VAR( isThermal ); + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; // static well control data bool const isProducer = wellControls.isProducer(); WellControls::Control const currentControl = wellControls.getControl(); @@ -788,7 +796,7 @@ PressureRelationKernel:: real64 localPresRel = 0; real64 localPresRelJacobian[2*(NC+1+IS_THERMAL)]{}; - compute< NC , IS_THERMAL >( + compute< NC, IS_THERMAL >( wellElemGravCoef[iwelem], wellElemGravCoef[iwelemNext], wellElemPressure[iwelem], @@ -835,10 +843,10 @@ PressureRelationKernel:: controlHasSwitched = ( switchControl.get() == 1 ); } -#define INST_PressureRelationKernel( NC , IS_THERMAL ) \ +#define INST_PressureRelationKernel( NC, IS_THERMAL ) \ template \ void PressureRelationKernel:: \ - launch< NC , IS_THERMAL >( localIndex const size, \ + launch< NC, IS_THERMAL >( localIndex const size, \ globalIndex const rankOffset, \ bool const isLocallyOwned, \ localIndex const iwelemControl, \ @@ -858,16 +866,16 @@ PressureRelationKernel:: CRSMatrixView< real64, globalIndex const > const & localMatrix, \ arrayView1d< real64 > const & localRhs ) -INST_PressureRelationKernel( 1, 0); -INST_PressureRelationKernel( 1, 1); -INST_PressureRelationKernel( 2, 0); -INST_PressureRelationKernel( 2, 1); -INST_PressureRelationKernel( 3, 0); -INST_PressureRelationKernel( 3, 1); -INST_PressureRelationKernel( 4, 0); -INST_PressureRelationKernel( 4 ,1); -INST_PressureRelationKernel( 5, 0); -INST_PressureRelationKernel( 5 ,1); +INST_PressureRelationKernel( 1, 0 ); +INST_PressureRelationKernel( 1, 1 ); +INST_PressureRelationKernel( 2, 0 ); +INST_PressureRelationKernel( 2, 1 ); +INST_PressureRelationKernel( 3, 0 ); +INST_PressureRelationKernel( 3, 1 ); +INST_PressureRelationKernel( 4, 0 ); +INST_PressureRelationKernel( 4, 1 ); +INST_PressureRelationKernel( 5, 0 ); +INST_PressureRelationKernel( 5, 1 ); /******************************** PerforationKernel ********************************/ @@ -906,7 +914,7 @@ PerforationKernel:: arraySlice3d< real64 > const & dCompPerfRate_dComp ) { using Deriv = multifluid::DerivativeOffset; - using CP_Deriv = multifluid::DerivativeOffsetC; + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; GEOS_UNUSED_VAR( dCompPerfRate ); // local working variables and arrays real64 pres[2]{}; @@ -1015,7 +1023,7 @@ PerforationKernel:: dPotDiff_dC[i][ic] += multiplier[i] * trans * dPres_dC[i][ic]; } // LHS & RHS both use CP_Deriv - for ( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) { dPotDiff[i][ic] += multiplier[i] * trans * dPres[i][ic]; } @@ -1117,7 +1125,7 @@ PerforationKernel:: + resPhaseMob * (dDens_dC[jc] / resDens - dVisc_dC[jc] / resVisc); } // Handles all dependencies - for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dMob[jc] = dRelPerm[jc] * resDens / resVisc + resPhaseMob * (dDens[jc] / resDens - dVisc[jc] / resVisc); @@ -1134,7 +1142,7 @@ PerforationKernel:: dFlux_dC[TAG::WELL][ic] = resPhaseMob * dPotDiff_dC[TAG::WELL][ic]; } // Handles all dependencies - for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dFlux[TAG::RES][jc] = dMob[jc] * potDiff + resPhaseMob * dPotDiff[TAG::RES][jc]; dFlux[TAG::WELL][jc] = resPhaseMob * dPotDiff[TAG::WELL][jc]; @@ -1178,7 +1186,7 @@ PerforationKernel:: &dCompFrac[CP_Deriv::dC], Deriv::dC ); - for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dCompPerfRate[TAG::RES][ic][jc] += dFlux[TAG::RES][jc] * resPhaseCompFrac[ip][ic]; dCompPerfRate[TAG::RES][ic][jc] += flux * dCompFrac[jc]; @@ -1188,14 +1196,14 @@ PerforationKernel:: } // tjb- remove when safe - for ( integer ic = 0; ic < NC; ic ++ ) + for( integer ic = 0; ic < NC; ic++ ) { - assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic]) < FLT_EPSILON); - assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic]) < FLT_EPSILON); - for ( integer jc = 0; jc < NC; ++jc) + assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic] ) < FLT_EPSILON ); + assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic] ) < FLT_EPSILON ); + for( integer jc = 0; jc < NC; ++jc ) { - assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc]) < FLT_EPSILON); - assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc]) < FLT_EPSILON); + assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc] ) < FLT_EPSILON ); + assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc] ) < FLT_EPSILON ); } } } @@ -1280,7 +1288,7 @@ PerforationKernel:: / ( resVisc * resVisc ); } // Handles all dependencies - for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc) + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dMob[jc] += (dRelPerm[jc] *resVisc - resRelPerm * dVisc[jc] ) / ( resVisc * resVisc); @@ -1304,11 +1312,11 @@ PerforationKernel:: { dMult[TAG::WELL][CP_Deriv::dT] = 0.0; } - for ( integer ic = 0; ic < NC; ++ic ) + for( integer ic = 0; ic < NC; ++ic ) { dMult[TAG::WELL][CP_Deriv::dC+ic] = resTotalMob; } - for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dMult[TAG::RES][jc] = wellElemTotalDens * dMob[jc]; } @@ -1325,7 +1333,7 @@ PerforationKernel:: dFlux_dC[TAG::WELL][ic] = dMult_dC[TAG::WELL][ic] * potDiff + mult * dPotDiff_dC[TAG::WELL][ic]; } - for ( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) { dFlux[TAG::RES][ic] = dMult[TAG::RES][ic] * potDiff + mult * dPotDiff[TAG::RES][ic]; dFlux[TAG::WELL][ic] = dMult[TAG::WELL][ic] * potDiff + mult * dPotDiff[TAG::WELL][ic]; @@ -1348,7 +1356,7 @@ PerforationKernel:: { // Note this needs to be include below when this code above is removed //compPerfRate[ic] += wellElemCompFrac[ic] * flux; - for ( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dCompPerfRate[TAG::RES][ic][jc] = wellElemCompFrac[ic] * dFlux[TAG::RES][jc]; } @@ -1367,24 +1375,24 @@ PerforationKernel:: } } // tjb- remove when safe - for ( integer ic = 0; ic < NC; ic ++ ) + for( integer ic = 0; ic < NC; ic++ ) { - if (fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic]) > FLT_EPSILON) + if( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic] ) > FLT_EPSILON ) { std::cout << ic << " " << dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] << " " << dCompPerfRate_dPres[TAG::RES][ic] << std::endl; } - assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic]) < FLT_EPSILON); - assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic]) < FLT_EPSILON); - for ( integer jc = 0; jc < NC; ++jc) + assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic] ) < FLT_EPSILON ); + assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic] ) < FLT_EPSILON ); + for( integer jc = 0; jc < NC; ++jc ) { - assert(fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc]) < FLT_EPSILON); - assert(fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc]) < FLT_EPSILON); + assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc] ) < FLT_EPSILON ); + assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc] ) < FLT_EPSILON ); } } } } -template< integer NC, integer NP , integer IS_THERMAL> +template< integer NC, integer NP, integer IS_THERMAL > void PerforationKernel:: launch( localIndex const size, @@ -1503,26 +1511,26 @@ PerforationKernel:: arrayView3d< real64 > const & dCompPerfRate_dPres, \ arrayView4d< real64 > const & dCompPerfRate_dComp ) -INST_PerforationKernel( 1, 2 , 0 ); -INST_PerforationKernel( 2, 2 , 0 ); -INST_PerforationKernel( 3, 2 , 0 ); -INST_PerforationKernel( 4, 2 , 0 ); -INST_PerforationKernel( 5, 2 , 0 ); -INST_PerforationKernel( 1, 3 , 0 ); -INST_PerforationKernel( 2, 3 , 0 ); -INST_PerforationKernel( 3, 3 , 0 ); -INST_PerforationKernel( 4, 3 , 0 ); -INST_PerforationKernel( 5, 3 , 0 ); -INST_PerforationKernel( 1, 2 , 1 ); -INST_PerforationKernel( 2, 2 , 1 ); -INST_PerforationKernel( 3, 2 , 1 ); -INST_PerforationKernel( 4, 2 , 1 ); -INST_PerforationKernel( 5, 2 , 1 ); -INST_PerforationKernel( 1, 3 , 1 ); -INST_PerforationKernel( 2, 3 , 1 ); -INST_PerforationKernel( 3, 3 , 1 ); -INST_PerforationKernel( 4, 3 , 1 ); -INST_PerforationKernel( 5, 3 , 1 ); +INST_PerforationKernel( 1, 2, 0 ); +INST_PerforationKernel( 2, 2, 0 ); +INST_PerforationKernel( 3, 2, 0 ); +INST_PerforationKernel( 4, 2, 0 ); +INST_PerforationKernel( 5, 2, 0 ); +INST_PerforationKernel( 1, 3, 0 ); +INST_PerforationKernel( 2, 3, 0 ); +INST_PerforationKernel( 3, 3, 0 ); +INST_PerforationKernel( 4, 3, 0 ); +INST_PerforationKernel( 5, 3, 0 ); +INST_PerforationKernel( 1, 2, 1 ); +INST_PerforationKernel( 2, 2, 1 ); +INST_PerforationKernel( 3, 2, 1 ); +INST_PerforationKernel( 4, 2, 1 ); +INST_PerforationKernel( 5, 2, 1 ); +INST_PerforationKernel( 1, 3, 1 ); +INST_PerforationKernel( 2, 3, 1 ); +INST_PerforationKernel( 3, 3, 1 ); +INST_PerforationKernel( 4, 3, 1 ); +INST_PerforationKernel( 5, 3, 1 ); /******************************** AccumulationKernel ********************************/ template< integer NC > diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 8e4eb98d267..466471040c9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -22,6 +22,7 @@ #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" +#include "common/KernelLaunchSelectors.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidFields.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" @@ -39,6 +40,7 @@ namespace geos { + namespace compositionalMultiphaseWellKernels { @@ -67,13 +69,28 @@ struct ColOffset static constexpr integer DCOMP = 1; }; -template < integer NC > -struct ColOffset_WellJac +template< integer NC, integer IS_THERMAL > +struct ColOffset_WellJac; + +template< integer NC > +struct ColOffset_WellJac< NC, 0 > +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static integer constexpr nDer = dQ + 1; + +}; + +template< integer NC > +struct ColOffset_WellJac< NC, 1 > { static constexpr integer dP = 0; static constexpr integer dC = 1; static constexpr integer dQ = dC + NC; static constexpr integer dT = dQ+1; +/// number of derivatives + static integer constexpr nDer = dT + 1; }; // define the row offset of the residual equations @@ -83,13 +100,27 @@ struct RowOffset static constexpr integer MASSBAL = 1; }; -template < integer NC > -struct RowOffset_WellJac +template< integer NC, integer IS_THERMAL > +struct RowOffset_WellJac; + +template< integer NC > +struct RowOffset_WellJac< NC, 0 > +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer nEqn = VOLBAL+1; +}; + +template< integer NC > +struct RowOffset_WellJac< NC, 1 > { static constexpr integer CONTROL = 0; static constexpr integer MASSBAL = 1; static constexpr integer VOLBAL = MASSBAL + NC; static constexpr integer ENERGYBAL = VOLBAL+1; +static constexpr integer nEqn = ENERGYBAL+1; + }; /******************************** ControlEquationHelper ********************************/ struct ControlEquationHelper @@ -113,7 +144,7 @@ struct ControlEquationHelper real64 const & currentTotalVolRate, WellControls::Control & newControl ); - template< integer NC , integer IS_THERMAL > + template< integer NC, integer IS_THERMAL > GEOS_HOST_DEVICE inline static void @@ -206,7 +237,7 @@ struct PressureRelationKernel using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - template< integer NC ,integer IS_THERMAL > + template< integer NC, integer IS_THERMAL > GEOS_HOST_DEVICE inline static void @@ -225,7 +256,7 @@ struct PressureRelationKernel real64 & localPresRel, real64 ( &localPresRelJacobian )[2*(NC+1+IS_THERMAL)] ); - template< integer NC , integer IS_THERMAL > + template< integer NC, integer IS_THERMAL > static void launch( localIndex const size, globalIndex const rankOffset, @@ -288,7 +319,7 @@ struct PerforationKernel using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - template< integer NC, integer NP , integer IS_THERMAL> + template< integer NC, integer NP, integer IS_THERMAL > GEOS_HOST_DEVICE inline static void @@ -359,6 +390,7 @@ struct PerforationKernel }; + /******************************** AccumulationKernel ********************************/ struct AccumulationKernel @@ -808,7 +840,7 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_totalDens_n[iwelem][0] ); } // Step 3: compute a normalizer for the volume balance equations - else + else if( idof == ROFFSET::MASSBAL + m_numComp ) { if( m_isProducer ) // only PHASEVOLRATE is supported for now { @@ -828,13 +860,15 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > } +} + // to make sure that everything still works well if the rate is zero, we add this check normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); - } - normalizer = LvArray::math::max( m_minNormalizer, normalizer ); - + // Step 4: compute the contribution to the residual +std::cout << "bNormalize " << idof << " " << stack.localRow + idof << " " << m_localResidual[stack.localRow + idof] << " " << normalizer << std::endl; real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; +std::cout << "Normalizer " << val << " " << stack.localValue[0] << std::endl; if( val > stack.localValue[0] ) { stack.localValue[0] = val; @@ -1038,23 +1072,30 @@ class SolutionCheckKernelFactory /** * @class ElementBasedAssemblyKernel * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom + * @tparam IS_THERMAL thermal switch * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance */ -template< integer NUM_COMP, integer NUM_DOF > +template< integer NUM_COMP, integer IS_THERMAL > class ElementBasedAssemblyKernel { public: using COFFSET = compositionalMultiphaseWellKernels::ColOffset; using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + + // Well jacobian column and row indicies + // tjb - change NUM_DOF to IS_THERMAL + using FLUID_PROP_COFFSET = multifluid::DerivativeOffsetC< NUM_COMP, IS_THERMAL >; + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NUM_COMP, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NUM_COMP, IS_THERMAL >; /// Compile time value for the number of components static constexpr integer numComp = NUM_COMP; - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; + /// Number of Dof's set in this kernal + static constexpr integer numDof = NUM_COMP + 1 + IS_THERMAL; /// Compute time value for the number of equations - static constexpr integer numEqn = NUM_DOF; + static constexpr integer numEqn = NUM_COMP + 1 + IS_THERMAL; + /** * @brief Constructor @@ -1114,14 +1155,14 @@ class ElementBasedAssemblyKernel localIndex localRow = -1; /// Indices of the matrix rows/columns corresponding to the dofs in this element - globalIndex dofIndices[numDof]{}; - globalIndex eqnRowIndices[numComp+1]{}; - globalIndex dofColIndices[numComp+1]{}; + globalIndex dofIndices[numDof]{}; // NC compdens + P + thermal + globalIndex eqnRowIndices[numDof]{}; + globalIndex dofColIndices[numDof]{}; - /// C-array storage for the element local residual vector (all equations except volume balance) + /// C-array storage for the element local residual vector (all equations except constraint and momentum) real64 localResidual[numEqn]{}; - /// C-array storage for the element local Jacobian matrix (all equations except volume balance, all dofs) + /// C-array storage for the element local Jacobian matrix (all equations except constraint and momentum) real64 localJacobian[numEqn][numDof]{}; }; @@ -1147,22 +1188,37 @@ class ElementBasedAssemblyKernel { // initialize the volume stack.volume = m_volume[ei]; - // set row index and degrees of freedom indices for this element (mass + vol bal) - for( integer ic = 0; ic < numComp+1; ++ic ) + + // Note row/col indices needed to be consistent with layout of stack.localJacobian + // Setup row equation indices for this element ( mass + vol + thermal if valid) + + // 1) Mass Balance + for( integer ic = 0; ic < numComp; ++ic ) { - stack.eqnRowIndices[ic] = m_dofNumber[ei] + ROFFSET::MASSBAL + ic - m_rankOffset; + stack.eqnRowIndices[ic] = m_dofNumber[ei] + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; } - - // set DOF col indices for this block ( mass + vol bal) - for( integer idof = 0; idof < numComp+1; ++idof ) +// 2) Volume Balance + stack.eqnRowIndices[numComp] = m_dofNumber[ei] + WJ_ROFFSET::VOLBAL - m_rankOffset; + // 3) Energy Balance + if constexpr ( IS_THERMAL ) + { + stack.eqnRowIndices[numComp+1] = m_dofNumber[ei] + WJ_ROFFSET::ENERGYBAL - m_rankOffset; + } + // Setup equation column indices for this element ( P + COMPDENS + THERMAL if valid) + stack.dofColIndices[0] = m_dofNumber[ei] + WJ_COFFSET::dP; + for( integer ic = 0; ic < numComp; ++ic ) { - stack.dofColIndices[idof] = m_dofNumber[ei] + COFFSET::DPRES + idof; + stack.dofColIndices[ic+1] = m_dofNumber[ei] + WJ_COFFSET::dC+ic; } - if ( 0) - for ( integer jc = 0; jc < numEqn; ++jc ) + if constexpr ( IS_THERMAL ) + { + stack.dofColIndices[numComp+1] = m_dofNumber[ei] + WJ_COFFSET::dT; + } + if( 0 ) + for( integer jc = 0; jc < numEqn; ++jc ) { stack.localResidual[jc] = 0.0; - for ( integer ic = 0; ic < numDof; ++ic ) + for( integer ic = 0; ic < numDof; ++ic ) { stack.localJacobian[jc][ic] = 0.0; } @@ -1203,6 +1259,7 @@ class ElementBasedAssemblyKernel arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; // temporary work arrays +real64 dPhaseAmount[FLUID_PROP_COFFSET::nDer]{}; real64 dPhaseAmount_dC[numComp]{}; real64 dPhaseCompFrac_dC[numComp]{}; @@ -1210,20 +1267,33 @@ class ElementBasedAssemblyKernel for( integer ip = 0; ip < m_numPhases; ++ip ) { real64 const phaseAmount = stack.volume * phaseVolFrac[ip] * phaseDens[ip]; +std::cout << " phaseAmount " << ip << " " << phaseVolFrac[ip] << " " << phaseDens[ip] << std::endl; real64 const phaseAmount_n = stack.volume * phaseVolFrac_n[ip] * phaseDens_n[ip]; - +std::cout << " phaseAmount_n " << ip << " " << phaseVolFrac[ip] << " " << phaseDens[ip] << std::endl; + //remove tjb real64 const dPhaseAmount_dP = stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); +dPhaseAmount[FLUID_PROP_COFFSET::dP]=stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); // assemble density dependence applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); +applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], &dPhaseAmount[FLUID_PROP_COFFSET::dC], Deriv::dC ); for( integer jc = 0; jc < numComp; ++jc ) { dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; dPhaseAmount_dC[jc] *= stack.volume; +dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] = dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] * phaseVolFrac[ip] + + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; + dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] *= stack.volume; } +// tjb- remove when safe + for( integer ic = 0; ic < numComp; ic++ ) + { + assert( fabs( dPhaseAmount[FLUID_PROP_COFFSET::dC+ic] -dPhaseAmount_dC[ic] ) < FLT_EPSILON ); +} // ic - index of component whose conservation equation is assembled // (i.e. row number in local matrix) for( integer ic = 0; ic < numComp; ++ic ) @@ -1245,15 +1315,24 @@ class ElementBasedAssemblyKernel for( integer jc = 0; jc < numComp; ++jc ) { real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmount - + phaseCompFrac[ip][ic] * dPhaseAmount_dC[jc]; + + phaseCompFrac[ip][ic] * dPhaseAmount[FLUID_PROP_COFFSET::dC+jc]; stack.localJacobian[ic][jc + 1] += dPhaseCompAmount_dC; } } - +if constexpr ( IS_THERMAL ) + { + dPhaseAmount[FLUID_PROP_COFFSET::dT] = stack.volume * (dPhaseVolFrac[ip][Deriv::dT] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dT] ); + for( integer ic = 0; ic < numComp; ++ic ) + { + // assemble the derivatives of the component mass balance equations with respect to temperature + stack.localJacobian[ic][numComp+1] += dPhaseAmount[FLUID_PROP_COFFSET::dT] * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dT]; + } + } // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives - // possible use: assemble the derivatives wrt temperature, and the accumulation term of the energy equation for this phase - phaseAmountKernelOp( ip, phaseAmount, phaseAmount_n, dPhaseAmount_dP, dPhaseAmount_dC ); + // possible use: assemble accumulation term of the energy equation for this phase + phaseAmountKernelOp( ip, phaseAmount, phaseAmount_n, dPhaseAmount ); } @@ -1275,11 +1354,10 @@ class ElementBasedAssemblyKernel * @param[inout] stack the stack variables * @param[in] phaseVolFractionSumKernelOp the function used to customize the kernel */ - template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE void computeVolumeBalance( localIndex const ei, - StackVariables & stack, - FUNC && phaseVolFractionSumKernelOp = NoOpFunc{} ) const + StackVariables & stack ) const { using Deriv = multifluid::DerivativeOffset; @@ -1289,6 +1367,8 @@ class ElementBasedAssemblyKernel real64 oneMinusPhaseVolFracSum = 1.0; // sum contributions to component accumulation from each phase +// Note localJacobian stores equation balances in order of component/vol/enerqy + // These are mapped to solver orderings with indicies setup in stack variables for( integer ip = 0; ip < m_numPhases; ++ip ) { oneMinusPhaseVolFracSum -= phaseVolFrac[ip]; @@ -1298,16 +1378,17 @@ class ElementBasedAssemblyKernel { stack.localJacobian[numComp][jc+1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; } - } - - // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives - // possible use: assemble the derivatives wrt temperature, and use oneMinusPhaseVolFracSum if poreVolume depends on temperature - // tjb revisit - phaseVolFractionSumKernelOp( oneMinusPhaseVolFracSum ); + + if constexpr ( IS_THERMAL) + { + stack.localJacobian[numComp][numComp+1] -= dPhaseVolFrac[ip][Deriv::dT]; + } + } // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) stack.localResidual[numComp] = stack.volume * oneMinusPhaseVolFracSum; - for( integer idof = 0; idof < numComp+1; ++idof ) + std::cout << "vol bal res " << stack.localResidual[numComp] << std::endl; + for( integer idof = 0; idof < numComp+1+IS_THERMAL; ++idof ) { stack.localJacobian[numComp][idof] *= stack.volume; } @@ -1329,23 +1410,29 @@ class ElementBasedAssemblyKernel if( m_kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) { // apply equation/variable change transformation to the component mass balance equations - real64 work[numComp + 1]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp+1, stack.localJacobian, work ); + real64 work[numComp + 1 + IS_THERMAL]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp+1+ IS_THERMAL, stack.localJacobian, work ); +for( integer i=0; i( stack.eqnRowIndices[i], stack.dofColIndices, stack.localJacobian[i], - numComp+1 ); + numComp+1+ IS_THERMAL ); } } @@ -1463,20 +1550,20 @@ class ElementBasedAssemblyKernelFactory CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + geos::internal::kernelLaunchSelectorCompThermSwitch( numComps, 0, [&]( auto NC, auto IS_THERMAL ) { localIndex constexpr NUM_COMP = NC(); localIndex constexpr NUM_DOF = NC()+2; +integer constexpr istherm = IS_THERMAL(); BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > + ElementBasedAssemblyKernel< NUM_COMP, istherm > kernel( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); + ElementBasedAssemblyKernel< NUM_COMP, istherm >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, istherm > >( subRegion.size(), kernel ); } ); } }; @@ -1487,7 +1574,7 @@ class ElementBasedAssemblyKernelFactory * @brief Define the interface for the assembly kernel in charge of flux terms */ template< integer NC, integer NUM_DOF > -class FaceBasedAssemblyKernel +class FaceBasedAssemblyKernel_ORG { public: @@ -1505,6 +1592,7 @@ class FaceBasedAssemblyKernel /** * @brief Constructor for the kernel interface +* @param[in] dt time step size * @param[in] rankOffset the offset of my MPI rank * @param[in] stencilWrapper reference to the stencil wrapper * @param[in] dofNumberAccessor @@ -1517,7 +1605,7 @@ class FaceBasedAssemblyKernel * @param[inout] localRhs the local right-hand side vector * @param[in] kernelFlags flags packed together */ - FaceBasedAssemblyKernel( real64 const dt, + FaceBasedAssemblyKernel_ORG( real64 const dt, globalIndex const rankOffset, string const wellDofKey, WellControls const & wellControls, @@ -1619,7 +1707,7 @@ class FaceBasedAssemblyKernel void computeFlux( localIndex const iwelem, FUNC && compFluxKernelOp = NoOpFunc{} ) const { - +GEOS_UNUSED_VAR( compFluxKernelOp ); using namespace compositionalMultiphaseUtilities; // create local work arrays @@ -1829,6 +1917,7 @@ class FaceBasedAssemblyKernel } } } +//compFluxKernelOp(iwelemNext,iwelemUp,currentConnRate, offsetUp, offsetCurrent); } @@ -1870,6 +1959,676 @@ class FaceBasedAssemblyKernel /// Connection rate arrayView1d< real64 const > const m_connRate; + + /// Element component fraction + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; + /// Element component fraction derivatives + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + /// Kernel option flag + integer const m_useTotalMassEquation; + + /// Well type + bool const m_isProducer; + + /// Injection stream composition + arrayView1d< real64 const > const m_injection; + + +}; + +template< integer NC, integer IS_THERMAL > +class FaceBasedAssemblyKernel +{ +public: + + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using TAG = compositionalMultiphaseWellKernels::ElemTag; + + using FLUID_PROP_COFFSET = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Number of Dof's set in this kernal + static constexpr integer numDof = WJ_COFFSET::nDer; + + /// Compile time value for the number of equations except rate, momentum, energy + static constexpr integer numEqn = NC; + + static constexpr integer maxNumElems = 2; + static constexpr integer maxStencilSize = 2; + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + FaceBasedAssemblyKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellControls const & wellControls, + ElementSubRegionBase const & subRegion, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + : + m_dt( dt ), + m_rankOffset( rankOffset ), + m_wellElemDofNumber ( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), + m_nextWellElemIndex ( subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString()) ), + m_connRate ( subRegion.getField< fields::well::mixtureConnectionRate >() ), + m_wellElemCompFrac ( subRegion.getField< fields::well::globalCompFraction >() ), + m_dWellElemCompFrac_dCompDens ( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ), + m_localMatrix( localMatrix ), + m_localRhs ( localRhs ), + m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ), + m_isProducer ( wellControls.isProducer() ), + m_injection ( wellControls.getInjectionStream() ) + { } + + struct StackVariables + { +public: + + /** + * @brief Constructor for the stack variables + * @param[in] size size of the stencil for this connection + * @param[in] numElems number of elements for this connection + */ + GEOS_HOST_DEVICE + StackVariables( localIndex const size ) + : stencilSize( size ), + numConnectedElems( 2 ), + dofColIndices( size * numDof ) + {} + + // Stencil information + localIndex const stencilSize; + /// Number of elements connected at a given connection + localIndex numConnectedElems; + + + // edge indexes + globalIndex offsetUp; + globalIndex offsetCurrent; + globalIndex offsetNext; + // Local degrees of freedom and local residual/jacobian + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + stackArray1d< globalIndex, maxNumElems * numDof > dofColIndices; + + /// Storage for the face local residual vector (all mass bal equations) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix dC dP dT + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * CP_Deriv::nDer > localFluxJacobian; + /// Storage for the face local Jacobian matrix dQ only + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize > localFluxJacobian_dQ; + }; + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void setup( localIndex const iconn, + StackVariables & stack ) const + { + stack.numConnectedElems=2; + if( m_nextWellElemIndex[iconn] <0 ) + { + stack.numConnectedElems = 1; + } + stack.localFlux.resize( stack.numConnectedElems*numEqn ); + stack.localFluxJacobian.resize( stack.numConnectedElems * numEqn, stack.stencilSize * numDof ); + stack.localFluxJacobian_dQ.resize( stack.numConnectedElems * numEqn, 1 ); + + } + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack ) const + { + using namespace compositionalMultiphaseUtilities; + if( stack.numConnectedElems ==1 ) + { + // Setup Jacobian global row indicies + // equations for COMPONENT + ENERGY balances + globalIndex oneSidedEqnRowIndices[numEqn]{}; + for( integer ic = 0; ic < NC; ++ic ) + { + oneSidedEqnRowIndices[ic] = stack.offsetUp + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) + globalIndex oneSidedDofColIndices_dPresCompTempUp[CP_Deriv::nDer]{}; + globalIndex oneSidedDofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; + // Note localFluxJacobian cols are stored using CP_Deriv order (dP dC or dP dT dC) + int ioff=0; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; + + if constexpr ( IS_THERMAL ) + { + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; + } + for( integer jdof = 0; jdof < NC; ++jdof ) + { + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; + } + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[CP_Deriv::nDer]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, 1, stack.localFluxJacobian_dQ, work ); + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, CP_Deriv::nDer, stack.localFluxJacobian, work ); + for( integer ic=0; ic= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + &oneSidedDofColIndices_dRate, + stack.localFluxJacobian_dQ[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + oneSidedDofColIndices_dPresCompTempUp, + stack.localFluxJacobian[i], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], stack.localFlux[i] ); + std::cout << " aa " << i << " " << oneSidedEqnRowIndices[i] << " " << m_localRhs[oneSidedEqnRowIndices[i]] << std::endl; + } + } + } + else + { + // Setup Jacobian global row indicies + // equations for COMPONENT + ENERGY balances + globalIndex eqnRowIndices[2*numEqn]{}; + + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + eqnRowIndices[TAG::NEXT *numEqn+ic] = stack.offsetNext + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; + eqnRowIndices[TAG::CURRENT *numEqn+ic] = stack.offsetCurrent + WJ_ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) + globalIndex dofColIndices_dPresCompUp[CP_Deriv::nDer]{}; + globalIndex dofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; + + int ioff=0; + // Indice storage order reflects local jac col storage order + dofColIndices_dPresCompUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; + + if constexpr ( IS_THERMAL ) + { + dofColIndices_dPresCompUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; + } + for( integer jdof = 0; jdof < NC; ++jdof ) + { + dofColIndices_dPresCompUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; + } + + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[CP_Deriv::nDer]{}; + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, numEqn, 1, 2, stack.localFluxJacobian_dQ, work ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, numEqn, CP_Deriv::nDer, 2, stack.localFluxJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numEqn, numEqn, 2, stack.localFlux ); + } + // Note this updates diag and offdiag + for( integer i = 0; i < 2*NC; ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], + &dofColIndices_dRate, + stack.localFluxJacobian_dQ[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices_dPresCompUp, + stack.localFluxJacobian[i], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], stack.localFlux[i] ); + } + } + } + } + + GEOS_HOST_DEVICE + inline + void + computeExit( real64 const & dt, + real64 const ( &compFlux )[NC ], + real64 const ( &dCompFlux_dRate )[NC ], + real64 const ( &dCompFlux_dPresUp )[NC ], + real64 const ( &dCompFlux_dCompDensUp )[NC ][NC], + real64 ( & oneSidedFlux )[NC], + real64 ( & oneSidedFluxJacobian_dRate )[NC][1], + real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1], + StackVariables & stack, + real64 ( & dCompFlux)[NC][numDof] ) const + { + for( integer ic = 0; ic < NC; ++ic ) + { + oneSidedFlux[ic] = -dt * compFlux[ic]; + stack.localFlux[ic] = -dt * compFlux[ic]; + std::cout << "ce wellflux " << dt << " ic " << ic << " " << stack.localFlux[ic] << std::endl; + // derivative with respect to rate + oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; + stack.localFluxJacobian_dQ[ic][0] = -dt * dCompFlux[ic][WJ_COFFSET::dQ]; + assert( fabs( dCompFlux[ic][WJ_COFFSET::dQ]- dCompFlux_dRate[ic] ) < FLT_EPSILON ); + // derivative with respect to upstream pressure + oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; + stack.localFluxJacobian[ic][CP_Deriv::dP] = -dt * dCompFlux[ic][WJ_COFFSET::dP]; + assert( fabs( dCompFlux_dPresUp[ic]- dCompFlux[ic][WJ_COFFSET::dP] ) < FLT_EPSILON ); + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; + stack.localFluxJacobian[ic][CP_Deriv::dC+jdof] = -dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; + assert( fabs( dCompFlux[ic][WJ_COFFSET::dC+jdof]- dCompFlux_dCompDensUp[ic][jdof] ) < FLT_EPSILON ); + } + if constexpr ( IS_THERMAL ) + { + stack.localFluxJacobian[ic][CP_Deriv::dT] = -dt * dCompFlux[ic][WJ_COFFSET::dT]; + } + } + for( integer ic = 0; ic < NC; ++ic ) + { + assert( fabs( stack.localFluxJacobian_dQ[ic][0]-oneSidedFluxJacobian_dRate[ic][0] ) < FLT_EPSILON ); + assert( fabs( stack.localFluxJacobian[ic][CP_Deriv::dP]-oneSidedFluxJacobian_dPresCompUp[ic][0] ) < FLT_EPSILON ); + for( integer jdof = 0; jdof < NC; ++jdof ) + { + assert( fabs( stack.localFluxJacobian[ic][CP_Deriv::dC+jdof]-oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] ) < FLT_EPSILON ); + } + } + } + + GEOS_HOST_DEVICE + inline + void + compute( real64 const & dt, + real64 const ( &compFlux )[NC ], + real64 const ( &dCompFlux_dRate )[NC ], + real64 const ( &dCompFlux_dPresUp )[NC ], + real64 const ( &dCompFlux_dCompDensUp )[NC ][NC], + real64 ( & localFlux )[2*NC], + real64 ( & localFluxJacobian_dRate )[2*NC][1], + real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1], + StackVariables & stack, + real64 ( & dCompFlux)[(NC )][numDof] ) const + { + // flux terms + for( integer ic = 0; ic < NC; ++ic ) + { + localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; + localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; + stack.localFlux[TAG::NEXT * NC +ic] = dt * compFlux[ic]; + stack.localFlux[TAG::CURRENT * NC +ic] = -dt * compFlux[ic]; + // derivative with respect to rate + localFluxJacobian_dRate[TAG::NEXT * NC + ic][0] = dt * dCompFlux_dRate[ic]; + localFluxJacobian_dRate[TAG::CURRENT * NC +ic][0] = -dt * dCompFlux_dRate[ic]; + stack.localFluxJacobian_dQ[TAG::NEXT * NC+ ic][0] = dt * dCompFlux[ic][WJ_COFFSET::dQ]; + stack.localFluxJacobian_dQ[TAG::CURRENT * NC + +ic][0] = -dt * dCompFlux[ic][WJ_COFFSET::dQ]; + + + // derivative with respect to upstream pressure + localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][0] = dt * dCompFlux_dPresUp[ic]; + localFluxJacobian_dPresCompUp[TAG::CURRENT * NC+ ic][0] = -dt * dCompFlux_dPresUp[ic]; + + stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dP] = dt * dCompFlux[ic][WJ_COFFSET::dP]; + stack.localFluxJacobian[TAG::CURRENT * NC+ ic][CP_Deriv::dP] = -dt * dCompFlux[ic][WJ_COFFSET::dP]; + + if constexpr ( IS_THERMAL ) + { + stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dT] = dt * dCompFlux[ic][WJ_COFFSET::dT]; + stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dT] = -dt * dCompFlux[ic][WJ_COFFSET::dT]; + } + + // derivatives with respect to upstream component densities + for( integer jdof = 0; jdof < NC; ++jdof ) + { + localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; + localFluxJacobian_dPresCompUp[TAG::CURRENT * NC +ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; + stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dC+jdof] = dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; + stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dC+jdof] = -dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; + } + } + for( integer ic = 0; ic < NC; ++ic ) + { + assert( fabs( stack.localFluxJacobian_dQ[TAG::NEXT * NC +ic][0]-localFluxJacobian_dRate[TAG::NEXT * NC +ic][0] ) < FLT_EPSILON ); + assert( fabs( stack.localFluxJacobian_dQ[TAG::CURRENT * NC +ic][0]-localFluxJacobian_dRate[TAG::CURRENT * NC +ic][0] ) < FLT_EPSILON ); + assert( fabs( stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dP]-localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][0] ) < FLT_EPSILON ); + assert( fabs( stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dP]-localFluxJacobian_dPresCompUp[TAG::CURRENT * NC +ic][0] ) < FLT_EPSILON ); + for( integer jdof = 0; jdof < NC; ++jdof ) + { + assert( fabs( stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dC+jdof]-localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][jdof+1] ) < FLT_EPSILON ); + assert( fabs( stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dC+jdof]-localFluxJacobian_dPresCompUp[TAG::CURRENT * NC +ic][jdof+1] ) < FLT_EPSILON ); + } + } + } + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iwelem, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + using namespace compositionalMultiphaseUtilities; + + // create local work arrays + real64 compFracUp[NC]{}; + real64 dCompFrac_dCompDensUp[NC][NC]{}; + + real64 compFlux[NC]{}; + real64 dCompFlux_dRate[NC]{}; + real64 dCompFlux_dPresUp[NC]{}; + real64 dCompFlux_dCompDensUp[NC][NC]{}; + + real64 dCompFlux[NC][numDof]{}; + // Step 1) decide the upwind well element + + /* currentConnRate < 0 flow from iwelem to iwelemNext + * currentConnRate > 0 flow from iwelemNext to iwelem + * With this convention, currentConnRate < 0 at the last connection for a producer + * currentConnRate > 0 at the last connection for a injector + */ + + localIndex const iwelemNext = m_nextWellElemIndex[iwelem]; + real64 const currentConnRate = m_connRate[iwelem]; + localIndex iwelemUp = -1; + + if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + { + // we still need to define iwelemUp for Jacobian assembly + iwelemUp = iwelem; + + // just copy the injection stream into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_injection[ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFrac_dCompDensUp[ic][jc] = 0.0; + dCompFlux[ic][WJ_COFFSET::dC+jc] = 0.0; + } + } + } + else + { + // first set iwelemUp to the upstream cell + if( ( iwelemNext < 0 && m_isProducer ) // exit connection, producer + || currentConnRate < 0 ) // not an exit connection, iwelem is upstream + { + iwelemUp = iwelem; + } + else // not an exit connection, iwelemNext is upstream + { + iwelemUp = iwelemNext; + } + + // copy the vars of iwelemUp into compFrac + for( integer ic = 0; ic < NC; ++ic ) + { + compFracUp[ic] = m_wellElemCompFrac[iwelemUp][ic]; + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFlux[ic][WJ_COFFSET::dC+jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + dCompFrac_dCompDensUp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + } + } + } + + // Step 2) compute upstream transport coefficient + + for( integer ic = 0; ic < NC; ++ic ) + { + compFlux[ic] = compFracUp[ic] * currentConnRate; + dCompFlux_dRate[ic] = compFracUp[ic]; + dCompFlux[ic][WJ_COFFSET::dQ] = compFracUp[ic]; + dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure + dCompFlux[ic][WJ_COFFSET::dP] = 0.0; + if constexpr ( IS_THERMAL ) + { + dCompFlux[ic][WJ_COFFSET::dT] = 0.0; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dCompFlux[ic][WJ_COFFSET::dC+jc] = dCompFlux[ic][WJ_COFFSET::dC+jc] * currentConnRate; + dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; + } + } + + stack.offsetUp = m_wellElemDofNumber[iwelemUp]; + stack.offsetCurrent = m_wellElemDofNumber[iwelem]; + + if( iwelemNext < 0 ) // exit connection + { + // for this case, we only need NC mass conservation equations + // so we do not use the arrays initialized before the loop + real64 oneSidedFlux[NC]{}; + real64 oneSidedFluxJacobian_dRate[NC][1]{}; + real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; + + computeExit ( m_dt, + compFlux, + dCompFlux_dRate, + dCompFlux_dPresUp, + dCompFlux_dCompDensUp, + oneSidedFlux, + oneSidedFluxJacobian_dRate, + oneSidedFluxJacobian_dPresCompUp, + stack, + dCompFlux ); + + /* + globalIndex oneSidedEqnRowIndices[NC]{}; + globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; + globalIndex oneSidedDofColIndices_dRate = 0; + + // jacobian indices + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + oneSidedEqnRowIndices[ic] = stack.offsetUp + ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // in the dof ordering used in this class, there are 1 pressure dofs + // and NC compDens dofs before the rate dof in this block + localIndex const dRateColOffset = COFFSET::DCOMP + NC; + oneSidedDofColIndices_dRate = stack.offsetCurrent + dRateColOffset; + + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + // dofs are the **upstream** pressure and component densities + oneSidedDofColIndices_dPresCompUp[jdof] = stack.offsetUp + COFFSET::DPRES + jdof; + } + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NC + 1]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); + } + + for( integer i = 0; i < NC; ++i ) + { + if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + &oneSidedDofColIndices_dRate, + oneSidedFluxJacobian_dRate[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], + oneSidedDofColIndices_dPresCompUp, + oneSidedFluxJacobian_dPresCompUp[i], + NC+1 ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); + } + } + */ + } + else // not an exit connection + { + real64 localFlux[2*(NC)]{}; + real64 localFluxJacobian_dRate[2*NC][1]{}; + real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; + + compute( m_dt, + compFlux, + dCompFlux_dRate, + dCompFlux_dPresUp, + dCompFlux_dCompDensUp, + localFlux, + localFluxJacobian_dRate, + localFluxJacobian_dPresCompUp, + stack, + dCompFlux + ); + + /* + globalIndex eqnRowIndices[2*NC]{}; + globalIndex dofColIndices_dPresCompUp[NC+1]{}; + globalIndex dofColIndices_dRate = 0; + + stack.offsetNext = m_wellElemDofNumber[iwelemNext]; + + // jacobian indices + for( integer ic = 0; ic < NC; ++ic ) + { + // mass balance equations for all components + eqnRowIndices[TAG::NEXT *NC+ic] = stack.offsetNext + ROFFSET::MASSBAL + ic - m_rankOffset; + eqnRowIndices[TAG::CURRENT *NC+ic] = stack.offsetCurrent + ROFFSET::MASSBAL + ic - m_rankOffset; + } + + // in the dof ordering used in this class, there are 1 pressure dofs + // and NC compDens dofs before the rate dof in this block + localIndex const dRateColOffset = COFFSET::DCOMP + NC; + dofColIndices_dRate = stack.offsetCurrent + dRateColOffset; + + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + // dofs are the **upstream** pressure and component densities + dofColIndices_dPresCompUp[jdof] = stack.offsetUp + COFFSET::DPRES + jdof; + } + + if( m_useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NC + 1]{}; + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); + } + + for( integer i = 0; i < 2*NC; ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], + &dofColIndices_dRate, + localFluxJacobian_dRate[i], + 1 ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices_dPresCompUp, + localFluxJacobian_dPresCompUp[i], + NC+1 ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localFlux[i] ); + } + } + */ + } + + compFluxKernelOp( iwelemNext, iwelemUp, currentConnRate ); + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + typename KERNEL_TYPE::StackVariables stack( 1 ); + + kernelComponent.setup( ie, stack ); + kernelComponent.computeFlux( ie, stack ); + kernelComponent.complete( ie, stack ); + } ); + } + +protected: + /// Time step size + real64 const m_dt; + /// Rank offset for calculating row/col Jacobian indices + integer const m_rankOffset; + + /// Reference to the degree-of-freedom numbers + arrayView1d< globalIndex const > const m_wellElemDofNumber; + /// Next element index, needed since iterating over element nodes, not edges + arrayView1d< localIndex const > const m_nextWellElemIndex; + + /// Connection rate + arrayView1d< real64 const > const m_connRate; + + /// Element component fraction arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; /// Element component fraction derivatives @@ -1927,14 +2686,14 @@ class FaceBasedAssemblyKernelFactory isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 2; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); - using kernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF >; + using kernelType = FaceBasedAssemblyKernel< NUM_COMP, 0 >; kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, localMatrix, localRhs, kernelFlags ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp new file mode 100644 index 00000000000..93e22e4cb5d --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -0,0 +1,1059 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PerforationFluxKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_PERFORATIONFLUXLKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_PERFORATIONFLUXLKERNELS_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "common/KernelLaunchSelectors.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "mesh/ObjectManagerBase.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +//#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +//#include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellTags.hpp" +#include "physicsSolvers/fluidFlow/wells/WellFields.hpp" + + +namespace geos +{ + +struct NoOpStuct +{ + NoOpStuct(){} +}; + +namespace isothermalPerforationFluxKernels +{ + +using namespace constitutive; + + + +/******************************** PerforationFluxKernel ********************************/ + +template< integer NC, integer NP, integer IS_THERMAL > +class PerforationFluxKernel +{ +public: + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NP; + + /// Compile time value for thermal option + static constexpr integer isThermal = IS_THERMAL; + + using TAG = wellTags::SubRegionTag; + + using CompFlowAccessors = + StencilAccessors< fields::flow::pressure, + fields::flow::phaseVolumeFraction, + fields::flow::dPhaseVolumeFraction, + fields::flow::dGlobalCompFraction_dGlobalCompDensity >; + + using MultiFluidAccessors = + StencilMaterialAccessors< MultiFluidBase, + fields::multifluid::phaseDensity, + fields::multifluid::dPhaseDensity, + fields::multifluid::phaseViscosity, + fields::multifluid::dPhaseViscosity, + fields::multifluid::phaseCompFraction, + fields::multifluid::dPhaseCompFraction >; + + using RelPermAccessors = + StencilMaterialAccessors< RelativePermeabilityBase, + fields::relperm::phaseRelPerm, + fields::relperm::dPhaseRelPerm_dPhaseVolFraction >; + + + /** + * @brief The type for element-based non-constitutive data parameters. + * Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + PerforationFluxKernel ( PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + RelPermAccessors const & relPermAccessors, + bool const disableReservoirToWellFlow ): + m_resPres( compFlowAccessors.get( fields::flow::pressure {} )), + m_resPhaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} )), + m_dResPhaseVolFrac(compFlowAccessors.get( fields::flow::dPhaseVolumeFraction {} )), + m_dResCompFrac_dCompDens( compFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity {} )), + m_resPhaseDens( multiFluidAccessors.get( fields::multifluid::phaseDensity {} )), + m_dResPhaseDens( multiFluidAccessors.get( fields::multifluid::dPhaseDensity {} )), + m_resPhaseVisc( multiFluidAccessors.get( fields::multifluid::phaseViscosity {} )), + m_dResPhaseVisc( multiFluidAccessors.get( fields::multifluid::dPhaseViscosity {} )), + m_resPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::phaseCompFraction {} )), + m_dResPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::dPhaseCompFraction {} )), + m_resPhaseRelPerm( relPermAccessors.get( fields::relperm::phaseRelPerm {} )), + m_dResPhaseRelPerm_dPhaseVolFrac( relPermAccessors.get( fields::relperm::dPhaseRelPerm_dPhaseVolFraction {} )), + m_wellElemGravCoef( subRegion.getField< fields::well::gravityCoefficient >()), + m_wellElemPres( subRegion.getField< fields::well::pressure >()), + m_wellElemCompDens( subRegion.getField< fields::well::globalCompDensity >()), + m_wellElemTotalMassDens( subRegion.getField< fields::well::totalMassDensity >()), + m_dWellElemTotalMassDens( subRegion.getField< fields::well::dTotalMassDensity >()), + m_dWellElemTotalMassDens_dPres( subRegion.getField< fields::well::dTotalMassDensity_dPressure >()), + m_dWellElemTotalMassDens_dCompDens( subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >()), + m_wellElemCompFrac( subRegion.getField< fields::well::globalCompFraction >()), + m_dWellElemCompFrac_dCompDens( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >()), + m_perfGravCoef( perforationData->getField< fields::well::gravityCoefficient >()), + m_perfWellElemIndex( perforationData->getField< fields::perforation::wellElementIndex >()), + m_perfTrans( perforationData->getField< fields::perforation::wellTransmissibility >()), + m_resElementRegion( perforationData->getField< fields::perforation::reservoirElementRegion >()), + m_resElementSubRegion( perforationData->getField< fields::perforation::reservoirElementSubRegion >()), + m_resElementIndex( perforationData->getField< fields::perforation::reservoirElementIndex >()), + m_compPerfRate( perforationData->getField< fields::well::compPerforationRate >()), + m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate >()), + m_dCompPerfRate_dPres( perforationData->getField< fields::well::dCompPerforationRate_dPres >()), + m_dCompPerfRate_dComp( perforationData->getField< fields::well::dCompPerforationRate_dComp >()), + m_disableReservoirToWellFlow( disableReservoirToWellFlow ) + {} + +struct StackVariables + { +public: + /** + * @brief Constructor for the stack variables + */ + + GEOS_HOST_DEVICE + StackVariables() {} + + }; + + template< typename STRUCT = NoOpFunc > + GEOS_HOST_DEVICE + inline + void + computeFlux( localIndex const iperf, STRUCT && stack= NoOpFunc{} ) const + { + // get the index of the reservoir elem + localIndex const er = m_resElementRegion[iperf]; + localIndex const esr = m_resElementSubRegion[iperf]; + localIndex const ei = m_resElementIndex[iperf]; + + // get the index of the well elem + localIndex const iwelem = m_perfWellElemIndex[iperf]; + + using Deriv = multifluid::DerivativeOffset; + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + + // local working variables and arrays + real64 pres[2]{}; + real64 dPres_dP[2]{}; + real64 dPres_dC[2][NC]{}; + real64 dFlux_dP[2]{}; + real64 dFlux_dC[2][NC]{}; + real64 dMult_dP[2]{}; + real64 dMult_dC[2][NC]{}; + real64 dPotDiff_dP[2]{}; + real64 dPotDiff_dC[2][NC]{}; + real64 multiplier[2]{}; + + real64 dResTotalMob_dC[NC]{}; + real64 dDens_dC[NC]{}; + real64 dVisc_dC[NC]{}; + real64 dRelPerm_dC[NC]{}; + real64 dMob_dC[NC]{}; + real64 dCompFrac_dCompDens[NC]{}; + + // local working variables - compact + // All derivative quantiites generated are stored in arrays using CP_Deriv offsets + // The input well/reservoir quantites use the Deriv offsets + // The arrays using the deriv offsets have extra column for dT in isothermal cases + + real64 dPres[2][CP_Deriv::nDer]{}; + real64 dFlux[2][CP_Deriv::nDer]{}; + real64 dMob[CP_Deriv::nDer]{}; + real64 dPotDiff[2][CP_Deriv::nDer]{}; + real64 dCompFrac[CP_Deriv::nDer]{}; + + // Step 1: reset the perforation rates + // tjb - remove when safe + for( integer ic = 0; ic < NC; ++ic ) + { + m_compPerfRate[iperf][ic] = 0.0; + for( integer ke = 0; ke < 2; ++ke ) + { + m_dCompPerfRate_dPres[iperf][ke][ic] = 0.0; + for( integer jc = 0; jc < NC; ++jc ) + { + m_dCompPerfRate_dComp[iperf][ke][ic][jc] = 0.0; + } + } + } + for( integer ic = 0; ic < NC; ++ic ) + { + m_compPerfRate[iperf][ic] = 0.0; + for( integer ke = 0; ke < 2; ++ke ) + { + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + m_dCompPerfRate[iperf][ke][ic][jc] = 0.0; + } + } + } + if constexpr (IS_THERMAL ) + { + // initialize outputs + stack.m_energyPerfFlux[iperf]=0; + for( integer ke = 0; ke < 2; ++ke ) + { + for ( integer i = 0; i < CP_Deriv::nDer; ++i ) + { + stack.m_dEnergyPerfFlux[iperf][ke][i]=0; + } + } + } + + // Step 2: copy the variables from the reservoir and well element + + // a) get reservoir variables + + pres[TAG::RES] = m_resPres[er][esr][ei]; + dPres_dP[TAG::RES] = 1.0; + dPres[TAG::RES][CP_Deriv::dP] = 1.0; + multiplier[TAG::RES] = 1.0; + + // Here in the absence of a buoyancy term we assume that the reservoir cell is perforated at its center + // TODO: add a buoyancy term for the reservoir side here + + + // b) get well variables + + pres[TAG::WELL] = m_wellElemPres[iwelem]; + dPres_dP[TAG::WELL] = 1.0; + dPres[TAG::WELL][CP_Deriv::dP] = 1.0; + multiplier[TAG::WELL] = -1.0; + + real64 const gravD = ( m_perfGravCoef[iperf] - m_wellElemGravCoef[iwelem] ); + + pres[TAG::WELL] += m_wellElemTotalMassDens[iwelem] * gravD; + // Note RHS uses CP_Deriv while LHS uses Deriv !!! + dPres_dP[TAG::WELL] += m_dWellElemTotalMassDens_dPres[iwelem] * gravD; + dPres[TAG::WELL][CP_Deriv::dP] += m_dWellElemTotalMassDens_dPres[iwelem] * gravD; + if constexpr ( IS_THERMAL ) + { + dPres[TAG::WELL][CP_Deriv::dT] += m_dWellElemTotalMassDens[iwelem][Deriv::dT] * gravD; + } + for( integer ic = 0; ic < NC; ++ic ) + { + dPres_dC[TAG::WELL][ic] += m_dWellElemTotalMassDens_dCompDens[iwelem][ic] * gravD; + dPres[TAG::WELL][CP_Deriv::dC+ic] += m_dWellElemTotalMassDens[iwelem][Deriv::dC+ic] * gravD; + } + + + + // Step 3: compute potential difference + + real64 potDiff = 0.0; + for( integer i = 0; i < 2; ++i ) + { + potDiff += multiplier[i] * m_perfTrans[iperf] * pres[i]; + dPotDiff_dP[i] += multiplier[i] * m_perfTrans[iperf] * dPres_dP[i]; + + for( integer ic = 0; ic < NC; ++ic ) + { + dPotDiff_dC[i][ic] += multiplier[i] * m_perfTrans[iperf] * dPres_dC[i][ic]; + } + // LHS & RHS both use CP_Deriv + for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + { + dPotDiff[i][ic] += multiplier[i] * m_perfTrans[iperf] * dPres[i][ic]; + } + } + + + // Step 4: upwinding based on the flow direction + + real64 flux = 0.0; + if( potDiff >= 0 ) // ** reservoir cell is upstream ** + { + + // loop over phases, compute and upwind phase flux + // and sum contributions to each component's perforation rate + for( integer ip = 0; ip < NP; ++ip ) + { + + // skip the rest of the calculation if the phase is absent + // or if crossflow is disabled for injectors + bool const phaseExists = (m_resPhaseVolFrac[er][esr][ei][ip] > 0); + if( !phaseExists || m_disableReservoirToWellFlow ) + { + continue; + } + + // here, we have to recompute the reservoir phase mobility (not including density) + + // density + real64 const resDens = m_resPhaseDens[er][esr][ei][0][ip]; + real64 dDens[CP_Deriv::nDer]{}; + + real64 const dResDens_dP = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dP]; + dDens[CP_Deriv::dP] = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dDens[CP_Deriv::dT] = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dT]; + } + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseDens[er][esr][ei][0][ip], + dDens_dC, + Deriv::dC ); + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseDens[er][esr][ei][0][ip], + &dDens[CP_Deriv::dC], + Deriv::dC ); + // viscosity + real64 const resVisc = m_resPhaseVisc[er][esr][ei][0][ip]; + real64 dVisc[CP_Deriv::nDer]{}; + real64 const dResVisc_dP = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; + dVisc[CP_Deriv::dP] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dVisc[CP_Deriv::dT] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dT]; + } + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseVisc[er][esr][ei][0][ip], + dVisc_dC, + Deriv::dC ); + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseVisc[er][esr][ei][0][ip], + &dVisc[CP_Deriv::dC], + Deriv::dC ); + + // relative permeability + real64 const resRelPerm = m_resPhaseRelPerm[er][esr][ei][0][ip]; + real64 dRelPerm[CP_Deriv::nDer]{}; + real64 dResRelPerm_dP = 0.0; + for( integer jc = 0; jc < NC; ++jc ) + { + dRelPerm_dC[jc] = 0; + } + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dRelPerm[jc]=0; + } + for( integer jp = 0; jp < NP; ++jp ) + { + real64 const dResRelPerm_dS = m_dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dResRelPerm_dP += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dRelPerm_dC[jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + } + } + + // compute the reservoir phase mobility, including phase density + real64 const resPhaseMob = resDens * resRelPerm / resVisc; + real64 const dResPhaseMob_dPres = dResRelPerm_dP * resDens / resVisc + + resPhaseMob * (dResDens_dP / resDens - dResVisc_dP / resVisc); + for( integer jc = 0; jc < NC; ++jc ) + { + dMob_dC[jc] = dRelPerm_dC[jc] * resDens / resVisc + + resPhaseMob * (dDens_dC[jc] / resDens - dVisc_dC[jc] / resVisc); + } + // Handles all dependencies + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dMob[jc] = dRelPerm[jc] * resDens / resVisc + + resPhaseMob * (dDens[jc] / resDens - dVisc[jc] / resVisc); + } + + // compute the phase flux and derivatives using upstream cell mobility + flux = resPhaseMob * potDiff; + dFlux_dP[TAG::RES] = dResPhaseMob_dPres * potDiff + resPhaseMob * dPotDiff_dP[TAG::RES]; + dFlux_dP[TAG::WELL] = resPhaseMob * dPotDiff_dP[TAG::WELL]; + + for( integer ic = 0; ic < NC; ++ic ) + { + dFlux_dC[TAG::RES][ic] = dMob_dC[ic] * potDiff + resPhaseMob * dPotDiff_dC[TAG::RES][ic]; + dFlux_dC[TAG::WELL][ic] = resPhaseMob * dPotDiff_dC[TAG::WELL][ic]; + } + + // Handles all dependencies + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dFlux[TAG::RES][jc] = dMob[jc] * potDiff + resPhaseMob * dPotDiff[TAG::RES][jc]; + dFlux[TAG::WELL][jc] = resPhaseMob * dPotDiff[TAG::WELL][jc]; + } + // increment component fluxes + for( integer ic = 0; ic < NC; ++ic ) + { + m_compPerfRate[iperf][ic] += flux * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + + m_dCompPerfRate_dPres[iperf][TAG::RES][ic] += m_resPhaseCompFrac[er][esr][ei][0][ip][ic] * dFlux_dP[TAG::RES]; + m_dCompPerfRate_dPres[iperf][TAG::RES][ic] += m_dResPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP] * flux; + m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] += m_resPhaseCompFrac[er][esr][ei][0][ip][ic] * dFlux_dP[TAG::WELL]; + + applyChainRule( NC, + m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseCompFrac[er][esr][ei][0][ip][ic], + dCompFrac_dCompDens, + Deriv::dC ); + + for( integer jc = 0; jc < NC; ++jc ) + { + m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] += dFlux_dC[TAG::RES][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] += flux * dCompFrac_dCompDens[jc]; + m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] += dFlux_dC[TAG::WELL][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + } + } + // increment component fluxes + for( integer ic = 0; ic < NC; ++ic ) + { + // Note this needs to be uncommented out + // m_compPerfRate[iperf][ic] += flux * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + dCompFrac[CP_Deriv::dP] = m_dResPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP]; + if constexpr (IS_THERMAL) + { + dCompFrac[CP_Deriv::dT] = m_dResPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; + } + + applyChainRule( NC, + m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseCompFrac[er][esr][ei][0][ip][ic], + &dCompFrac[CP_Deriv::dC], + Deriv::dC ); + + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + m_dCompPerfRate[iperf][TAG::RES][ic][jc] += dFlux[TAG::RES][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + m_dCompPerfRate[iperf][TAG::RES][ic][jc] += flux * dCompFrac[jc]; + m_dCompPerfRate[iperf][TAG::WELL][ic][jc] += dFlux[TAG::WELL][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + } + } + + if constexpr ( IS_THERMAL ) + { + real64 const res_enthalpy = stack.m_resPhaseEnthalpy[er][esr][ei][0][ip]; + + stack.m_energyPerfFlux[iperf] += flux * res_enthalpy; + // energy equation derivatives WRT res P & T + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * res_enthalpy + + flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * res_enthalpy + + flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; + // energy equation derivatives WRT well P + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * res_enthalpy ; + // stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * res_enthalpy ; + + // energy equation derivatives WRT reservoir dens + real64 dProp_dC[numComp]{}; + applyChainRule( NC, + m_dResCompFrac_dCompDens[er][esr][ei], + stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + + for( integer jc = 0; jc < NC; ++jc ) + { + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dC+jc] += flux * dProp_dC[jc]; + } + } + } // end resevoir is upstream phase loop + + // tjb- remove when safe + for( integer ic = 0; ic < NC; ic++ ) + { + assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] ) < FLT_EPSILON ); + for( integer jc = 0; jc < NC; ++jc ) + { + assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] ) < FLT_EPSILON ); + } + } + } + else // ** well is upstream ** + { + + real64 resTotalMob = 0.0; + real64 dResTotalMob_dP = 0.0; + + // we re-compute here the total mass (when useMass == 1) or molar (when useMass == 0) density + real64 wellElemTotalDens = 0; + for( integer ic = 0; ic < NC; ++ic ) + { + wellElemTotalDens += m_wellElemCompDens[iwelem][ic]; + } + + // first, compute the reservoir total mobility (excluding phase density) + for( integer ip = 0; ip < NP; ++ip ) + { + + // skip the rest of the calculation if the phase is absent + bool const phaseExists = (m_resPhaseVolFrac[er][esr][ei][ip] > 0); + if( !phaseExists ) + { + continue; + } + + // viscosity + real64 const resVisc = m_resPhaseVisc[er][esr][ei][0][ip]; + real64 dVisc[CP_Deriv::nDer]{}; + real64 const dResVisc_dP = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; + dVisc[CP_Deriv::dP] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dVisc[CP_Deriv::dT] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dT]; + } + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseVisc[er][esr][ei][0][ip], + dVisc_dC, + Deriv::dC ); + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseVisc[er][esr][ei][0][ip], + &dVisc[CP_Deriv::dC], + Deriv::dC ); + + + // relative permeability + real64 const resRelPerm = m_resPhaseRelPerm[er][esr][ei][0][ip]; + real64 dRelPerm[CP_Deriv::nDer]{}; + real64 dResRelPerm_dP = 0.0; + for( integer jc = 0; jc < NC; ++jc ) + { + dRelPerm_dC[jc] = 0; + } + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dRelPerm[jc]=0; + } + for( integer jp = 0; jp < NP; ++jp ) + { + real64 const dResRelPerm_dS = m_dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dResRelPerm_dP += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + dRelPerm_dC[jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + } + } + // increment total mobility + resTotalMob += resRelPerm / resVisc; + + dResTotalMob_dP += ( dResRelPerm_dP * resVisc - resRelPerm * dResVisc_dP ) + / ( resVisc * resVisc ); + for( integer ic = 0; ic < NC; ++ic ) + { + dResTotalMob_dC[ic] += ( dRelPerm_dC[ic] * resVisc - resRelPerm * dVisc_dC[ic] ) + / ( resVisc * resVisc ); + } + // Handles all dependencies + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dMob[jc] += (dRelPerm[jc] *resVisc - resRelPerm * dVisc[jc] ) + / ( resVisc * resVisc); + } + } // end well is upstream phase loop + + // compute a potdiff multiplier = wellElemTotalDens * resTotalMob + // wellElemTotalDens is a mass density if useMass == 1 and a molar density otherwise + real64 const mult = wellElemTotalDens * resTotalMob; + dMult_dP[TAG::RES] = wellElemTotalDens * dResTotalMob_dP; + dMult_dP[TAG::WELL] = 0.0; // because totalDens does not depend on pressure + for( integer ic = 0; ic < NC; ++ic ) + { + dMult_dC[TAG::RES][ic] = wellElemTotalDens * dResTotalMob_dC[ic]; + dMult_dC[TAG::WELL][ic] = resTotalMob; + } + + real64 dMult[2][CP_Deriv::nDer]{}; + dMult[TAG::WELL][CP_Deriv::dP] = 0.0; + if constexpr ( IS_THERMAL ) + { + dMult[TAG::WELL][CP_Deriv::dT] = 0.0; + } + for( integer ic = 0; ic < NC; ++ic ) + { + dMult[TAG::WELL][CP_Deriv::dC+ic] = resTotalMob; + } + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + dMult[TAG::RES][jc] = wellElemTotalDens * dMob[jc]; + } + + + // compute the volumetric flux and derivatives using upstream cell mobility + flux = mult * potDiff; + dFlux_dP[TAG::RES] = dMult_dP[TAG::RES] * potDiff + mult * dPotDiff_dP[TAG::RES]; + dFlux_dP[TAG::WELL] = dMult_dP[TAG::WELL] * potDiff + mult * dPotDiff_dP[TAG::WELL]; + + for( integer ic = 0; ic < NC; ++ic ) + { + dFlux_dC[TAG::RES][ic] = dMult_dC[TAG::RES][ic] * potDiff + mult * dPotDiff_dC[TAG::RES][ic]; + dFlux_dC[TAG::WELL][ic] = dMult_dC[TAG::WELL][ic] * potDiff + mult * dPotDiff_dC[TAG::WELL][ic]; + } + + for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) + { + dFlux[TAG::RES][ic] = dMult[TAG::RES][ic] * potDiff + mult * dPotDiff[TAG::RES][ic]; + dFlux[TAG::WELL][ic] = dMult[TAG::WELL][ic] * potDiff + mult * dPotDiff[TAG::WELL][ic]; + } + // compute component fluxes + for( integer ic = 0; ic < NC; ++ic ) + { + m_compPerfRate[iperf][ic] += m_wellElemCompFrac[iwelem][ic] * flux; + m_dCompPerfRate_dPres[iperf][TAG::RES][ic] = m_wellElemCompFrac[iwelem][ic] * dFlux_dP[TAG::RES]; + m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] = m_wellElemCompFrac[iwelem][ic] * dFlux_dP[TAG::WELL]; + + for( integer jc = 0; jc < NC; ++jc ) + { + m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] += m_wellElemCompFrac[iwelem][ic] * dFlux_dC[TAG::RES][jc]; + m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] += m_wellElemCompFrac[iwelem][ic] * dFlux_dC[TAG::WELL][jc]; + m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] += m_dWellElemCompFrac_dCompDens[iwelem][ic][jc] * flux; + } + } + for( integer ic = 0; ic < NC; ++ic ) + { + // Note this needs to be include below when this code above is removed + // m_compPerfRate[iperf][ic] += m_wellElemCompFrac[iwelem][ic] * flux; + for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) + { + m_dCompPerfRate[iperf][TAG::RES][ic][jc] = m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::RES][jc]; + } + } + for( integer ic = 0; ic < NC; ++ic ) + { + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] = m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::WELL][CP_Deriv::dP]; + if constexpr ( IS_THERMAL ) + { + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dT] = m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::WELL][CP_Deriv::dT]; + } + for( integer jc = 0; jc < NC; ++jc ) + { + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] += m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::WELL][CP_Deriv::dC+jc]; + m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] += m_dWellElemCompFrac_dCompDens[iwelem][ic][jc] * flux; + } + } + if constexpr ( IS_THERMAL ) + { + for( integer ip = 0; ip < NP; ++ip ) + { + real64 const wellelem_enthalpy = stack.m_wellElemPhaseEnthalpy[iwelem][0][ip]; + stack.m_energyPerfFlux[iperf] += flux * wellelem_enthalpy; + // energy equation derivatives WRT res P & T + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy ; + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy ; + // energy equation derivatives WRT well P & T + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy + + flux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dP]; + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy + + flux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dT]; + + // energy equation derivatives WRT reservoir dens + real64 dProp_dC[numComp]{}; + applyChainRule( NC, + m_dWellElemCompFrac_dCompDens[iwelem], + &stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dC], + dProp_dC, + Deriv::dC ); + + for( integer jc = 0; jc < NC; ++jc ) + { + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dC+jc] += flux * dProp_dC[jc]; + } + } + } + // tjb- remove when safe + for( integer ic = 0; ic < NC; ic++ ) + { + if( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) > FLT_EPSILON ) + { + std::cout << ic << " " << m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] << " " << m_dCompPerfRate_dPres[iperf][TAG::RES][ic] << std::endl; + } + assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] ) < FLT_EPSILON ); + for( integer jc = 0; jc < NC; ++jc ) + { + assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] ) < FLT_EPSILON ); + } + } + //compFluxKernelOp(er, esr, ei, potDiff, potGrad, flux, dFlux); + } // end phase loop + } + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + { + + kernelComponent.computeFlux(iperf, kernelComponent.m_stackVariables); + + } ); + } + + +StackVariables m_stackVariables; + +protected: + ElementViewConst< arrayView1d< real64 const > > const m_resPres; + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_resPhaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dResPhaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dResCompFrac_dCompDens; + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseDens; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseDens; + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseVisc; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseVisc; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const m_resPhaseCompFrac; + ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const m_dResPhaseCompFrac; + ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const m_resPhaseRelPerm; + ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const m_dResPhaseRelPerm_dPhaseVolFrac; + arrayView1d< real64 const > const m_wellElemGravCoef; + arrayView1d< real64 const > const m_wellElemPres; + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompDens; + arrayView1d< real64 const > const m_wellElemTotalMassDens; + arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens; + arrayView1d< real64 const > const m_dWellElemTotalMassDens_dPres; + arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens_dCompDens; + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + arrayView1d< real64 const > const m_perfGravCoef; + arrayView1d< localIndex const > const m_perfWellElemIndex; + arrayView1d< real64 const > const m_perfTrans; + arrayView1d< localIndex const > const m_resElementRegion; + arrayView1d< localIndex const > const m_resElementSubRegion; + arrayView1d< localIndex const > const m_resElementIndex; + arrayView2d< real64 > const m_compPerfRate; + arrayView4d< real64 > const m_dCompPerfRate; + arrayView3d< real64 > const m_dCompPerfRate_dPres; + arrayView4d< real64 > const m_dCompPerfRate_dComp; + + bool const m_disableReservoirToWellFlow; + + +}; + +/** + * @class PerforationKernelFactory + */ +class PerforationFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhases, + string const flowSolverName, + PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + ElementRegionManager & elemManager, + integer const disableReservoirToWellFlow ) + { + geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases , [&]( auto NC, auto NP ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_PHASE = NP(); + integer constexpr IS_THERMAL = 0; + + using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); + //typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, flowSolverName ); + typename kernelType::RelPermAccessors relPermAccessors( elemManager ,flowSolverName ); + //ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + // elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + //dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + kernelType kernel( perforationData, subRegion, compFlowAccessors, multiFluidAccessors, relPermAccessors, disableReservoirToWellFlow ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + } +}; + +}; // end namespace isothermalPerforationFluxKernels + +namespace thermalPerforationFluxKernels +{ + +using namespace constitutive; + +/******************************** PerforationFluxKernel ********************************/ + +template< integer NC, integer NP, integer IS_THERMAL > +class PerforationFluxKernel : public isothermalPerforationFluxKernels::PerforationFluxKernel +{ +public: + + using Base = isothermalPerforationFluxKernels::PerforationFluxKernel; + //using AbstractBase::m_dPhaseVolFrac; + using Base::m_resPhaseCompFrac; + using Base::m_dResCompFrac_dCompDens; + //using AbstractBase::m_dPhaseCompFrac; + //using AbstractBase::m_dCompFrac_dCompDens; + /// Compile time value for the number of components + static constexpr integer numComp = NC; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NP; + + /// Compile time value for thermal option + static constexpr integer isThermal = IS_THERMAL; + + using TAG = typename Base::TAG; + using CompFlowAccessors = typename Base::CompFlowAccessors ; + using MultiFluidAccessors = typename Base::MultiFluidAccessors; + using RelPermAccessors = typename Base::RelPermAccessors; + + + using ThermalCompFlowAccessors = + StencilAccessors< fields::flow::temperature >; + + using ThermalMultiFluidAccessors = + StencilMaterialAccessors< MultiFluidBase, + fields::multifluid::phaseEnthalpy, + fields::multifluid::dPhaseEnthalpy >; + + //using ThermalConductivityAccessors = + // StencilMaterialAccessors< MultiPhaseThermalConductivityBase, + // fields::thermalconductivity::effectiveConductivity >; + + /** + * @brief The type for element-based non-constitutive data parameters. + * Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + PerforationFluxKernel ( PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + RelPermAccessors const & relPermAccessors, + bool const disableReservoirToWellFlow, + ThermalCompFlowAccessors const & thermalCompFlowAccessors, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors) + : Base(perforationData, + subRegion, + compFlowAccessors, + multiFluidAccessors, + relPermAccessors, + disableReservoirToWellFlow ), + m_stack(perforationData, + fluid, + thermalCompFlowAccessors, + thermalMultiFluidAccessors) + + //m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), + //m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), + // m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()) , + //m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) , + //m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + //m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + //m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) + + {} + + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( PerforationData * const perforationData, + MultiFluidBase const & fluid, + ThermalCompFlowAccessors const & thermalCompFlowAccessors, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors ) + : Base::StackVariables(), + m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), + m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), + m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()) , + m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) , + m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) + {} + + /// Views on phase enthalpy + arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; + + /// Views on energy flux + arrayView1d< real64 > const & m_energyPerfFlux; + arrayView3d< real64 > const & m_dEnergyPerfFlux; + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on phase enthalpies + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseEnthalpy; + }; + + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void + computeFlux( localIndex const iperf ) const + { + Base::computeFlux(iperf, m_stack ); + } + + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + { + //kernelComponent.setupStack(iperf); + kernelComponent.computeFlux(iperf); + + } ); + } + +protected: + + /// Stack continaining thermal variables + StackVariables m_stack; + + +}; + +/** + * @class PerforationKernelFactory + */ +class PerforationFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhases, + string const flowSolverName, + PerforationData * const perforationData, + ElementSubRegionBase const & subRegion, + MultiFluidBase const & fluid, + ElementRegionManager & elemManager, + integer const disableReservoirToWellFlow ) + { + geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases , [&]( auto NC, auto NP ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_PHASE = NP(); + integer constexpr IS_THERMAL = 1; + + using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); + //typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, flowSolverName ); + typename kernelType::RelPermAccessors relPermAccessors( elemManager ,flowSolverName ); + typename kernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, flowSolverName ); + typename kernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, flowSolverName ); + //typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, flowSolverName ); + //ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + // elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + //dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + kernelType kernel( perforationData, subRegion, fluid, compFlowAccessors, multiFluidAccessors, + relPermAccessors, disableReservoirToWellFlow, + thermalCompFlowAccessors, + thermalMultiFluidAccessors ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + } +}; + +} // end namespace thermalPerforationFluxKernels + +} // end namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_PERFORATIONFLUXLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 9f61be73ac7..0aef7c6701b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -21,9 +21,11 @@ #include "common/DataTypes.hpp" #include "common/FieldSpecificationOps.hpp" #include "common/TimingMacros.hpp" +#include "common/KernelLaunchSelectors.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" #include "constitutive/fluid/singlefluid/SingleFluidSelector.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/WellElementSubRegion.hpp" @@ -33,6 +35,7 @@ #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" namespace geos @@ -48,6 +51,8 @@ SinglePhaseWell::SinglePhaseWell( const string & name, { m_numDofPerWellElement = 2; m_numDofPerResElement = 1; +m_numPhases = 1; + m_numComponents = 1; } void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) @@ -66,6 +71,7 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) [&]( localIndex const, WellElementSubRegion & subRegion ) { + subRegion.registerField< fields::well::pressure_n >( getName() ); subRegion.registerField< fields::well::pressure >( getName() ). setRestartFlags( RestartFlags::WRITE_AND_READ ); @@ -83,9 +89,17 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) WellControls & wellControls = getWellControls( subRegion ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() ); +wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). + setSizedFromParent( 0 ). + reference().resizeDimension< 0 >( 2 ); // dP, dT wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentBHP_dPresString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentVolRateString() ); +wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentVolRateString() ). + setSizedFromParent( 0 ). + reference().resizeDimension< 0 >( 3 ); // dP, dT, dQ + + wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentVolRate_dPresString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentVolRate_dRateString() ); @@ -184,7 +198,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const & dens = fluid.density(); arrayView2d< real64 const > const & dDens_dPres = fluid.dDensity_dPressure(); - +arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); // control data WellControls & wellControls = getWellControls( subRegion ); @@ -194,23 +208,39 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) real64 & currentBHP = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ); +arrayView1d< real64 > const & dCurrentBHP = + wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentBHPString() ); + real64 & dCurrentBHP_dPres = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); // bring everything back to host, capture the scalars by reference - forAll< serialPolicy >( 1, [pres, + geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL ) { + integer constexpr IS_THERMAL = ISTHERMAL(); + //using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >; + using Deriv = multifluid::DerivativeOffset; + forAll< serialPolicy >( 1, [ pres, dens, dDens_dPres, +dDens_dTemp, wellElemGravCoef, ¤tBHP, +&dCurrentBHP, &dCurrentBHP_dPres, &iwelemRef, &refGravCoef] ( localIndex const ) { - currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * ( refGravCoef - wellElemGravCoef[iwelemRef] ); - dCurrentBHP_dPres = 1.0 + dDens_dPres[iwelemRef][0] * ( refGravCoef - wellElemGravCoef[iwelemRef] ); - } ); + real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; + currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * diffGravCoef; + dCurrentBHP[Deriv::dP] = 1.0 + dDens_dPres[iwelemRef][0] * diffGravCoef; + dCurrentBHP_dPres = 1.0 + dDens_dPres[iwelemRef][0] * diffGravCoef; + if constexpr ( IS_THERMAL ) + { + dCurrentBHP[Deriv::dT] = 1.0 + dDens_dTemp[iwelemRef][0] * diffGravCoef; + } + } ); + } ); if( logLevel >= 2 ) { GEOS_LOG_RANK( GEOS_FMT( "{}: The BHP (at the specified reference elevation) is {} Pa", @@ -244,7 +274,7 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const & dens = fluid.density(); arrayView2d< real64 const > const & dDens_dPres = fluid.dDensity_dPressure(); - +arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); // control data WellControls & wellControls = getWellControls( subRegion ); @@ -255,6 +285,9 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi real64 & currentVolRate = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() ); +arrayView1d< real64 > const & dCurrentVolRate = + wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentVolRateString() ); + real64 & dCurrentVolRate_dPres = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::dCurrentVolRate_dPresString() ); real64 & dCurrentVolRate_dRate = @@ -263,16 +296,20 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - +geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL ) { + integer constexpr IS_THERMAL = ISTHERMAL(); + using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >; // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [fluidWrapper, pres, connRate, dens, dDens_dPres, +dDens_dTemp, &useSurfaceConditions, &surfacePres, ¤tVolRate, +&dCurrentVolRate, &dCurrentVolRate_dPres, &dCurrentVolRate_dRate, &iwelemRef, @@ -305,7 +342,13 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi real64 const densInv = 1.0 / dens[iwelemRef][0]; currentVolRate = connRate[iwelemRef] * densInv; dCurrentVolRate_dPres = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; +dCurrentVolRate[COFFSET_WJ::dP] = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; dCurrentVolRate_dRate = densInv; +dCurrentVolRate[COFFSET_WJ::dQ] = densInv; + if constexpr ( IS_THERMAL ) + { + dCurrentVolRate[COFFSET_WJ::dT] = -( useSurfaceConditions == 0 ) * dDens_dTemp[iwelemRef][0] * currentVolRate * densInv; + } if( logLevel >= 2 && useSurfaceConditions ) { @@ -316,6 +359,7 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi } } ); } ); +} ); } void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const @@ -569,6 +613,53 @@ void SinglePhaseWell::assembleAccumulationTerms( DomainPartition const & domain, { GEOS_MARK_FUNCTION; +if( 1 ) + { + string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion const & subRegion ) + { + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + SingleFluidBase const & fluid = getConstitutiveModel< SingleFluidBase >( subRegion, fluidName ); + if( isThermal() ) + { + + thermalSinglePhaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + wellElemDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + + } + else + { + singlePhaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( + dofManager.rankOffset(), + wellElemDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + } ); + } ); + } + else + { forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & mesh, arrayView1d< string const > const & regionNames ) @@ -607,7 +698,7 @@ void SinglePhaseWell::assembleAccumulationTerms( DomainPartition const & domain, } ); } ); - +} } void SinglePhaseWell::assembleVolumeBalanceTerms( DomainPartition const & GEOS_UNUSED_PARAM( domain ), diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 9df8cfcec0f..4c3ea81271e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -245,9 +245,11 @@ class SinglePhaseWell : public WellSolverBase // control data (not registered on the mesh) static constexpr char const * currentBHPString() { return "currentBHP"; } +static constexpr char const * dCurrentBHPString() { return "dCurrentBHP"; } static constexpr char const * dCurrentBHP_dPresString() { return "dCurrentBHP_dPres"; } static constexpr char const * currentVolRateString() { return "currentVolumetricRate"; } +static constexpr char const * dCurrentVolRateString() { return "dCurrentVolumetricRate"; } static constexpr char const * dCurrentVolRate_dPresString() { return "dCurrentVolumetricRate_dPres"; } static constexpr char const * dCurrentVolRate_dRateString() { return "dCurrentVolumetricRate_dRate"; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp index f54b0bfd8bd..025044d59bb 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp @@ -35,6 +35,26 @@ namespace geos namespace singlePhaseWellKernels { + +template< integer IS_THERMAL > +struct ColOffset_WellJac {}; + + +template<> +struct ColOffset_WellJac< 0 > +{ + static constexpr integer dP = 0; + static constexpr integer dQ = 1; +}; +template<> +struct ColOffset_WellJac< 1 > +{ + static constexpr integer dP = 0; + static constexpr integer dQ = 1; + static constexpr integer dT = 2; +}; + + // tag to access well and reservoir elements in perforation rates computation struct SubRegionTag { @@ -500,6 +520,284 @@ struct SolutionCheckKernel } }; +/******************************** ElementBasedAssemblyKernel ********************************/ + +/** + * @class ElementBasedAssemblyKernel + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance + */ +template< integer NUM_DOF > +class ElementBasedAssemblyKernel +{ +public: + using ROFFSET = singlePhaseWellKernels::RowOffset; + using COFFSET = singlePhaseWellKernels::ColOffset; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations + static constexpr integer numEqn = NUM_DOF; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel( globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::SingleFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : + m_rankOffset( rankOffset ), + m_wellElemDofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), + m_elemGhostRank( subRegion.ghostRank() ), + m_wellElemVolume( subRegion.getElementVolume() ), + m_wellElemDensity( fluid.density() ), + m_wellElemDensity_n( fluid.density_n() ), + + m_dWellElemDensity_dPressure( fluid.dDensity_dPressure() ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + // volume information (used by both accumulation and volume balance) + real64 volume = 0.0; + real64 density = 0.0; + real64 density_n = 0.0; + real64 dDensity_dPres = 0.0; + + + // Residual information + + /// Index of the local row corresponding to this element + localIndex localRow = -1; + + /// Indices of the matrix rows/columns corresponding to the dofs in this element + globalIndex dofIndices[numDof]{}; + globalIndex eqnRowIndices[numDof]{}; + globalIndex dofColIndices[numDof]{}; + + /// C-array storage for the element local residual vector (all equations ) + real64 localResidual[numDof]{}; + + /// C-array storage for the element local Jacobian matrix (all equations , all dofs) + real64 localJacobian[numDof][numDof]{}; + + }; + /** + * @brief Getter for the ghost rank of an element + * @param[in] ei the element index + * @return the ghost rank of the element + */ + GEOS_HOST_DEVICE + integer elemGhostRank( localIndex const ei ) const + { return m_elemGhostRank( ei ); } + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] ei the element index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + // initialize the volume + stack.volume = m_wellElemVolume[ei]; + stack.density = m_wellElemDensity[ei][0]; + stack.density_n = m_wellElemDensity_n[ei][0]; + stack.dDensity_dPres = m_dWellElemDensity_dPressure[ei][0]; + + // set row index and degrees of freedom indices for this element (mass + vol bal) + for( integer ic = 0; ic < numDof; ++ic ) + { + stack.eqnRowIndices[ic] = m_wellElemDofNumber[ei] + ic - m_rankOffset; + } + + // set DOF col indices for this block ( mass + vol bal) + for( integer idof = 0; idof < numDof; ++idof ) + { + stack.dofColIndices[idof] = m_wellElemDofNumber[ei] + idof; + } + + for( integer jc = 0; jc < numDof; ++jc ) + { + stack.localResidual[jc] = 0.0; + for( integer ic = 0; ic < numDof; ++ic ) + { + stack.localJacobian[jc][ic] = 0.0; + } + + } + + } + + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseAmountKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const iwelem, + StackVariables & stack, + FUNC && KernelOp = NoOpFunc{} ) const + { + + localIndex const eqnRowIndex = m_wellElemDofNumber[iwelem] + ROFFSET::MASSBAL - m_rankOffset; + globalIndex const presDofColIndex = m_wellElemDofNumber[iwelem] + COFFSET::DPRES; + + stack.localResidual[0] = stack.volume * ( stack.density - stack.density_n ); + stack.localJacobian[0][1] = stack.volume * stack.dDensity_dPres; + + KernelOp(); + // check zero diagonal (works only in debug) + /* + for( integer ic = 0; ic < numComp; ++ic ) + { + GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, + GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); + } + */ + } + + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const GEOS_UNUSED_PARAM( ei ), + StackVariables & stack ) const + { + + // add contribution to residual and jacobian into: + // - mass bal + // - pressure eqn + // - energy if thermal + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + + for( integer i = 0; i < NUM_DOF; ++i ) + { + m_localRhs[stack.eqnRowIndices[i]] += stack.localResidual[i]; + m_localMatrix.template addToRow< serialAtomic >( stack.eqnRowIndices[i], + stack.dofColIndices, + stack.localJacobian[i], + numDof ); + } + + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) + { + if( kernelComponent.elemGhostRank( iwelem ) >= 0 ) + { + return; + } + typename KERNEL_TYPE::StackVariables stack; + kernelComponent.setup( iwelem, stack ); + kernelComponent.computeAccumulation( iwelem, stack ); + kernelComponent.complete( iwelem, stack ); + + } ); + } + +protected: + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_wellElemDofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_elemGhostRank; + + /// View on the element volumes + arrayView1d< real64 const > const m_wellElemVolume; + + /// Views on the densities + arrayView2d< real64 const > const m_wellElemDensity; + arrayView2d< real64 const > const m_wellElemDensity_n; + arrayView2d< real64 const > const m_dWellElemDensity_dPressure; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + +}; + + +/** + * @class ElementBasedAssemblyKernelFactory + */ +class ElementBasedAssemblyKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::SingleFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + integer constexpr NUM_DOF = 2; + ElementBasedAssemblyKernel< NUM_DOF > + kernel( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ); + ElementBasedAssemblyKernel< NUM_DOF >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_DOF > >( subRegion.size(), kernel ); + + } +}; } // end namespace singlePhaseWellKernels } // end namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 2e04d48d829..e459b685117 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -20,7 +20,7 @@ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" - +#include "physicsSolvers/SolverBaseKernels.hpp" namespace geos { @@ -138,19 +138,313 @@ class TotalMassDensityKernelFactory } }; +/******************************** ResidualNormKernel ********************************/ + +/** + * @class ResidualNormKernel + */ +template< localIndex NUM_COMP > +class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 2 > +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NUM_COMP, 1 >; + + using Base = solverBaseKernels::ResidualNormKernelBase< 2 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + ResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + integer const targetPhaseIndex, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + WellControls const & wellControls, + real64 const timeAtEndOfStep, + real64 const dt, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_numPhases( fluid.numFluidPhases()), + m_targetPhaseIndex( targetPhaseIndex ), + m_dt( dt ), + m_isLocallyOwned( subRegion.isLocallyOwned() ), + m_iwelemControl( subRegion.getTopWellElementIndex() ), + m_isProducer( wellControls.isProducer() ), + m_currentControl( wellControls.getControl() ), + m_targetBHP( wellControls.getTargetBHP( timeAtEndOfStep ) ), + m_targetTotalRate( wellControls.getTargetTotalRate( timeAtEndOfStep ) ), + m_targetPhaseRate( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ), + m_targetMassRate( wellControls.getTargetMassRate( timeAtEndOfStep ) ), + m_volume( subRegion.getElementVolume() ), + m_phaseDens_n( fluid.phaseDensity_n() ), + m_totalDens_n( fluid.totalDensity_n() ), + m_phaseVolFraction_n( subRegion.getField< fields::well::phaseVolumeFraction_n >()), + m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() ) + {} + + + GEOS_HOST_DEVICE + void computeMassEnergyNormalizers( localIndex const iwelem, + real64 & massNormalizer, + real64 & energyNormalizer ) const + { + massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[iwelem][0] * m_volume[iwelem] ); + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + energyNormalizer += m_phaseInternalEnergy_n[iwelem][0][ip] * m_phaseDens_n[iwelem][0][ip] * m_phaseVolFraction_n[iwelem][ip] * m_volume[iwelem]; + } + // warning: internal energy can be negative + energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( energyNormalizer ) ); + } + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const iwelem, + LinfStackVariables & stack ) const override + { + real64 normalizer = 0.0; + for( integer idof = 0; idof < WJ_ROFFSET::nEqn; ++idof ) + { + + // Step 1: compute a normalizer for the control or pressure equation + + // for the control equation, we distinguish two cases + if( idof == WJ_ROFFSET::CONTROL ) + { + + // for the top well element, normalize using the current control + if( m_isLocallyOwned && iwelem == m_iwelemControl ) + { + if( m_currentControl == WellControls::Control::BHP ) + { + // the residual entry is in pressure units + normalizer = m_targetBHP; + } + else if( m_currentControl == WellControls::Control::TOTALVOLRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetTotalRate ), m_minNormalizer ); + } + else if( m_currentControl == WellControls::Control::PHASEVOLRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetPhaseRate ), m_minNormalizer ); + } + else if( m_currentControl == WellControls::Control::MASSRATE ) + { + // the residual entry is in volume / time units + normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer ); + } + } + // for the pressure difference equation, always normalize by the BHP + else + { + normalizer = m_targetBHP; + } + } + // Step 2: compute a normalizer for the mass balance equations + else if( idof >= WJ_ROFFSET::MASSBAL && idof < WJ_ROFFSET::MASSBAL + numComp ) + { + if( m_isProducer ) // only PHASEVOLRATE is supported for now + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex]; + } + else // Type::INJECTOR, only TOTALVOLRATE is supported for now + { + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate ); + } + else + { + // the residual is in mass units + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0]; + } + + } + + // to make sure that everything still works well if the rate is zero, we add this check + normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_totalDens_n[iwelem][0] ); + } + // Step 3: compute a normalizer for the volume balance equations + else if( idof == WJ_ROFFSET::VOLBAL ) + { + if( m_isProducer ) // only PHASEVOLRATE is supported for now + { + // the residual is in volume units + normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ); + } + else // Type::INJECTOR, only TOTALVOLRATE is supported for now + { + if( m_currentControl == WellControls::Control::MASSRATE ) + { + normalizer = m_dt * LvArray::math::abs( m_targetMassRate/ m_totalDens_n[iwelem][0] ); + } + else + { + normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ); + } + + } + // to make sure that everything still works well if the rate is zero, we add this check + normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); + } + // step 3: energy residual + if( idof == WJ_ROFFSET::ENERGYBAL ) + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( iwelem, massNormalizer, energyNormalizer ); + real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + WJ_ROFFSET::ENERGYBAL] ) / energyNormalizer; + if( valEnergy > stack.localValue[1] ) + { + stack.localValue[1] = valEnergy; + } + + } + else + { + + normalizer = LvArray::math::max( m_minNormalizer, normalizer ); + + // Step 4: compute the contribution to the residual + std::cout << "bNormalize " << idof << " " << stack.localRow + idof << " " << m_localResidual[stack.localRow + idof] << " " << normalizer << std::endl; + real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; + std::cout << "Normalizer " << val << " " << stack.localValue[0] << std::endl; + if( val > stack.localValue[0] ) + { + stack.localValue[0] = val; + } + } + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const iwelem, + L2StackVariables & stack ) const override + { + GEOS_UNUSED_VAR( iwelem, stack ); + GEOS_ERROR( "The L2 norm is not implemented for CompositionalMultiphaseWell" ); + } + + +protected: + + /// Number of fluid phases + integer const m_numPhases; + + /// Index of the target phase + integer const m_targetPhaseIndex; + + /// Time step size + real64 const m_dt; + + /// Flag indicating whether the well is locally owned or not + bool const m_isLocallyOwned; + + /// Index of the element where the control is enforced + localIndex const m_iwelemControl; + + /// Flag indicating whether the well is a producer or an injector + bool const m_isProducer; + + /// Controls + WellControls::Control const m_currentControl; + real64 const m_targetBHP; + real64 const m_targetTotalRate; + real64 const m_targetPhaseRate; + real64 const m_targetMassRate; + + /// View on the volume + arrayView1d< real64 const > const m_volume; + + /// View on phase/total density at the previous converged time step + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens_n; + arrayView2d< real64 const, multifluid::USD_FLUID > const m_totalDens_n; + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFraction_n; + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseInternalEnergy_n; + +}; + +/* + *@class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComp number of fluid components + * @param[in] numDof number of dofs per well element + * @param[in] targetPhaseIndex the index of the target phase (for phase volume control) + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] localResidual the residual vector on my MPI rank + * @param[in] subRegion the well element subregion + * @param[in] fluid the fluid model + * @param[in] wellControls the controls + * @param[in] timeAtEndOfStep the time at the end of the step (time_n + dt) + * @param[in] dt the time step size + * @param[out] residualNorm the residual norm on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const targetPhaseIndex, + globalIndex const rankOffset, + string const & dofKey, + arrayView1d< real64 const > const & localResidual, + WellElementSubRegion const & subRegion, + MultiFluidBase const & fluid, + WellControls const & wellControls, + real64 const timeAtEndOfStep, + real64 const dt, + real64 const minNormalizer, + real64 (& residualNorm)[2] ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch ( numComp, [&]( auto NC ) + { + + integer constexpr NUM_COMP = NC(); + using kernelType = ResidualNormKernel< NUM_COMP >; + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + kernelType kernel( rankOffset, localResidual, dofNumber, ghostRank, + targetPhaseIndex, subRegion, fluid, wellControls, timeAtEndOfStep, dt, minNormalizer ); + kernelType::template launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } ); + } + +}; + /******************************** ElementBasedAssemblyKernel ********************************/ /** * @class ElementBasedAssemblyKernel * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom + * @tparam IS_THERMAL thermal flag * @brief Define the interface for the assembly kernel in charge of thermal accumulation and volume balance */ -template< localIndex NUM_COMP, localIndex NUM_DOF > -class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > +template< localIndex NUM_COMP > +class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, 1 > { public: - using Base = compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >; + using Base = compositionalMultiphaseWellKernels::ElementBasedAssemblyKernel< NUM_COMP, 1 >; using Base::m_dCompFrac_dCompDens; using Base::m_dofNumber; using Base::m_dPhaseCompFrac; @@ -175,6 +469,9 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El using Base::numDof; using Base::numEqn; + using FLUID_PROP_COFFSET = multifluid::DerivativeOffsetC< NUM_COMP, 1 >; + + /** * @brief Constructor * @param[in] numPhases the number of fluid phases @@ -227,6 +524,8 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El { Base::setup( ei, stack ); + + } /** @@ -241,7 +540,10 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El { using Deriv = multifluid::DerivativeOffset; - Base::computeAccumulation( ei, stack, [&]( integer const ip, real64 const & phaseAmount, real64 const & phaseAmount_n, real64 const & dPhaseAmount_dP, real64 const (&dPhaseAmount_dC)[numComp] ) + Base::computeAccumulation( ei, stack, [&]( integer const ip + , real64 const & phaseAmount + , real64 const & phaseAmount_n + , real64 const (&dPhaseAmount)[FLUID_PROP_COFFSET::nDer] ) { // We are in the loop over phases, ip provides the current phase index. // We have to do two things: @@ -262,37 +564,31 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseInternalEnergy = m_dPhaseInternalEnergy[ei][0]; - // Step 1: assemble the derivatives of the component mass balance equations with respect to temperature - - real64 const dPhaseAmount_dT = stack.volume * (dPhaseVolFrac[ip][Deriv::dT] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dT] ); - for( integer ic = 0; ic < numComp; ++ic ) - { - stack.localJacobian[ic][numDof-1] += dPhaseAmount_dT * phaseCompFrac[ip][ic] - + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dT]; - } - - // Step 2: assemble the phase-dependent part of the accumulation term of the energy equation + // Step 1: assemble the phase-dependent part of the accumulation term of the energy equation real64 const phaseEnergy = phaseAmount * phaseInternalEnergy[ip]; real64 const phaseEnergy_n = phaseAmount_n * phaseInternalEnergy_n[ip]; - real64 const dPhaseEnergy_dP = dPhaseAmount_dP * phaseInternalEnergy[ip] + real64 const dPhaseEnergy_dP = dPhaseAmount[FLUID_PROP_COFFSET::dP] * phaseInternalEnergy[ip] + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP]; - real64 const dPhaseEnergy_dT = dPhaseAmount_dT * phaseInternalEnergy[ip] + real64 const dPhaseEnergy_dT = dPhaseAmount[FLUID_PROP_COFFSET::dT] * phaseInternalEnergy[ip] + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dT]; - +std::cout << "wellthermaccum " << ip << " " << dPhaseAmount[FLUID_PROP_COFFSET::dT] << " " << phaseInternalEnergy[ip] + << " " << phaseAmount << " " << dPhaseInternalEnergy[ip][Deriv::dT] << std::endl; // local accumulation stack.localResidual[numEqn-1] += phaseEnergy - phaseEnergy_n; // derivatives w.r.t. pressure and temperature stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP; stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; +std::cout << " ip " << ip << " " << stack.localJacobian[numEqn-1][0] << " " << stack.localJacobian[numEqn-1][numDof-1] << std::endl; // derivatives w.r.t. component densities applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); for( integer jc = 0; jc < numComp; ++jc ) { - stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount_dC[jc] + stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] + dPhaseInternalEnergy_dC[jc] * phaseAmount; +std::cout << "therm accu " << numEqn-1 << " " << jc+1 << " " << stack.localJacobian[numEqn-1][jc + 1] << std::endl; } } ); @@ -309,19 +605,8 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El void computeVolumeBalance( localIndex const ei, StackVariables & stack ) const { - using Deriv = multifluid::DerivativeOffset; - - Base::computeVolumeBalance( ei, stack, [&]( real64 const & oneMinusPhaseVolFraction ) - { - GEOS_UNUSED_VAR( oneMinusPhaseVolFraction ); + Base::computeVolumeBalance( ei, stack ); - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - stack.localJacobian[numEqn-2][numDof-1] -= dPhaseVolFrac[ip][Deriv::dT]; - } - } ); } GEOS_HOST_DEVICE @@ -330,6 +615,8 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El { // Step 1: assemble the component mass balance equations and volume balance equations Base::complete( ei, stack ); + + /* fix me tjb // Step 2: assemble the energy equation m_localRhs[stack.localRow + numEqn - 1] += stack.localResidual[numEqn - 1]; @@ -385,42 +672,57 @@ class ElementBasedAssemblyKernelFactory internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { localIndex constexpr NUM_COMP = NC(); - localIndex constexpr NUM_DOF = NC()+2; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > + ElementBasedAssemblyKernel< NUM_COMP > kernel( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); + ElementBasedAssemblyKernel< NUM_COMP >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP > >( subRegion.size(), kernel ); } ); } }; /** * @class FaceBasedAssemblyKernel * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @brief Define the interface for the assembly kernel in charge of flux terms + * @brief Define the interface for the assembly kernel in charge of flux terms */ -template< integer NC, integer NUM_DOF > -class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, NUM_DOF > +template< integer NC > +class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, 1 > { public: +static constexpr integer IS_THERMAL = 1; + using Base = compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, IS_THERMAL >; + + // Well jacobian column and row indicies + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; - using Base = compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, NUM_DOF >; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; using TAG = compositionalMultiphaseWellKernels::ElemTag; + using Base::m_isProducer; + using Base::m_dt; + using Base::m_localRhs; + using Base::m_localMatrix; + using Base::m_rankOffset; + using Base::maxNumElems; + using Base::maxStencilSize; + using Base::m_useTotalMassEquation; + /// Compile time value for the number of components static constexpr integer numComp = NC; /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; + static constexpr integer numDof = WJ_COFFSET::nDer; +/// Compile time value for the number of equations except volume and momentum + static constexpr integer numEqn = WJ_ROFFSET::nEqn - 2; /** * @brief Constructor for the kernel interface @@ -441,83 +743,89 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB string const wellDofKey, WellControls const & wellControls, ElementSubRegionBase const & subRegion, +MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) - : Base( dt , rankOffset , subRegion.getReference< array1d< globalIndex > >( wellDofKey ) - , subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString()) - , subRegion.getField< fields::well::mixtureConnectionRate >() - , subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() + : Base( dt + , rankOffset + , wellDofKey + , wellControls + , subRegion , localMatrix , localRhs - , kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) - , wellControls.isProducer() - , wellControls.getInjectionStream() ) + , kernelFlags ), + m_numPhases ( fluid.numFluidPhases()), + m_phaseFraction( fluid.phaseFraction()), + m_dPhaseFraction( fluid.dPhaseFraction()), + m_phaseEnthalpy( fluid.phaseEnthalpy()), + m_dPhaseEnthalpy( fluid.dPhaseEnthalpy()) { } - - GEOS_HOST_DEVICE - inline - void - computeExit( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & oneSidedFlux )[NC], - real64 ( & oneSidedFluxJacobian_dRate )[NC][1], - real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ) const +struct StackVariables : public Base::StackVariables { - for( integer ic = 0; ic < NC; ++ic ) - { - oneSidedFlux[ic] = -dt * compFlux[ic]; +public: - // derivative with respect to rate - oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; + GEOS_HOST_DEVICE + StackVariables( localIndex const size ) + : Base::StackVariables( size ) + {} - // derivative with respect to upstream pressure - oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; + /// Storage for the face local residual vector (energy equation) + stackArray1d< real64, maxNumElems > localEnergyFlux; + /// Storage for the face local energy Jacobian matrix dC dP dT + stackArray2d< real64, maxNumElems * maxStencilSize * CP_Deriv::nDer > localEnergyFluxJacobian; + /// Storage for the face local Jacobian matrix dQ only + stackArray2d< real64, maxNumElems * maxStencilSize > localEnergyFluxJacobian_dQ; + }; - // derivatives with respect to upstream component densities - for( integer jdof = 0; jdof < NC; ++jdof ) - { - oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; - } - } + GEOS_HOST_DEVICE + inline + void setup( localIndex const iwelem, StackVariables & stack ) const + { + Base::setup ( iwelem, stack ); + stack.localEnergyFlux.resize( stack.numConnectedElems ); + stack.localEnergyFluxJacobian.resize( stack.numConnectedElems, stack.stencilSize * numDof ); + stack.localEnergyFluxJacobian_dQ.resize( stack.numConnectedElems, 1 ); } GEOS_HOST_DEVICE inline - void - compute( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & localFlux )[2*NC], - real64 ( & localFluxJacobian_dRate )[2*NC][1], - real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ) const + void complete( localIndex const iwelem, StackVariables & stack ) const { - // flux terms - for( integer ic = 0; ic < NC; ++ic ) + Base::complete ( iwelem, stack ); + using namespace compositionalMultiphaseUtilities; + if( stack.numConnectedElems ==1 ) { - localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; - localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; + // Setup Jacobian global row indicies for energy equation + globalIndex oneSidedEqnRowIndices = stack.offsetUp + WJ_ROFFSET::ENERGYBAL - m_rankOffset; - // derivative with respect to rate - localFluxJacobian_dRate[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dRate[ic]; - localFluxJacobian_dRate[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dRate[ic]; + // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) + globalIndex oneSidedDofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; + globalIndex oneSidedDofColIndices_dPresCompTempUp[CP_Deriv::nDer]{}; - // derivative with respect to upstream pressure - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dPresUp[ic]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dPresUp[ic]; - - // derivatives with respect to upstream component densities + int ioff=0; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; for( integer jdof = 0; jdof < NC; ++jdof ) { - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; + } + + + if( oneSidedEqnRowIndices >= 0 && oneSidedEqnRowIndices < m_localMatrix.numRows() ) + { + m_localMatrix.template addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices, + &oneSidedDofColIndices_dRate, + stack.localEnergyFluxJacobian_dQ[0], + 1 ); + m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices, + oneSidedDofColIndices_dPresCompTempUp, + stack.localEnergyFluxJacobian[0], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices], stack.localEnergyFlux[0] ); } + } } @@ -528,222 +836,85 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB * @param[inout] stack the stack variables * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes */ - template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE inline - void computeFlux( localIndex const iwelem, - FUNC && compFluxKernelOp = NoOpFunc{} ) const + void computeFlux( localIndex const iwelem, StackVariables & stack ) const { - - using namespace compositionalMultiphaseUtilities; - - // create local work arrays - real64 compFracUp[NC]{}; - real64 dCompFrac_dCompDensUp[NC][NC]{}; - - real64 compFlux[NC]{}; - real64 dCompFlux_dRate[NC]{}; - real64 dCompFlux_dPresUp[NC]{}; - real64 dCompFlux_dCompDensUp[NC][NC]{}; - - // Step 1) decide the upwind well element - - /* currentConnRate < 0 flow from iwelem to iwelemNext - * currentConnRate > 0 flow from iwelemNext to iwelem - * With this convention, currentConnRate < 0 at the last connection for a producer - * currentConnRate > 0 at the last connection for a injector - */ - - localIndex const iwelemNext = m_nextWellElemIndex[iwelem]; - real64 const currentConnRate = m_connRate[iwelem]; - localIndex iwelemUp = -1; - - if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + Base::computeFlux ( iwelem, stack, [&] ( localIndex const & iwelemNext + , localIndex const & iwelemUp + , real64 const & currentConnRate ) { - // we still need to define iwelemUp for Jacobian assembly - iwelemUp = iwelem; - // just copy the injection stream into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = m_injection[ic]; - for( integer jc = 0; jc < NC; ++jc ) + if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + { + real64 eflux=0; + real64 eflux_dq=0; + for( integer ip = 0; ip < m_numPhases; ++ip ) { - dCompFrac_dCompDensUp[ic][jc] = 0.0; + std::cout << "eflux " << ip << " " << m_phaseEnthalpy[iwelemUp][0][ip] << " " << m_phaseFraction[iwelemUp][0][ip] << std::endl; + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; } + // Energy equation + stack.localEnergyFlux[0] = -m_dt * eflux * currentConnRate; + stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt * eflux_dq; } - } - else - { - // first set iwelemUp to the upstream cell - if( ( iwelemNext < 0 && m_isProducer ) // exit connection, producer - || currentConnRate < 0 ) // not an exit connection, iwelem is upstream + else if( ( iwelemNext < 0 && m_isProducer ) || currentConnRate < 0 ) // exit connection, producer { - iwelemUp = iwelem; - } - else // not an exit connection, iwelemNext is upstream - { - iwelemUp = iwelemNext; - } - - // copy the vars of iwelemUp into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = m_wellElemCompFrac[iwelemUp][ic]; - for( integer jc = 0; jc < NC; ++jc ) + real64 eflux=0; + real64 eflux_dq=0; + for( integer ip = 0; ip < m_numPhases; ++ip ) { - dCompFrac_dCompDensUp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; + for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) + { + std::cout << " wellflux " << ip << " " << dof << " " << m_phaseEnthalpy[iwelemUp][0][ip] << " " << m_dPhaseFraction[iwelemUp][0][ip][dof] + << " " << m_dPhaseEnthalpy[iwelemUp][0][ip][dof] << " " << m_phaseFraction[iwelemUp][0][ip] << std::endl; + stack.localEnergyFluxJacobian[0] [dof] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][dof] + + m_dPhaseEnthalpy[iwelemUp][0][ip][dof]*m_phaseFraction[iwelemUp][0][ip]; + + } } - } - } - - // Step 2) compute upstream transport coefficient - - for( integer ic = 0; ic < NC; ++ic ) - { - compFlux[ic] = compFracUp[ic] * currentConnRate; - dCompFlux_dRate[ic] = compFracUp[ic]; - dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; - } - } - - globalIndex const offsetUp = m_wellElemDofNumber[iwelemUp]; - globalIndex const offsetCurrent = m_wellElemDofNumber[iwelem]; - - if( iwelemNext < 0 ) // exit connection - { - // for this case, we only need NC mass conservation equations - // so we do not use the arrays initialized before the loop - real64 oneSidedFlux[NC]{}; - real64 oneSidedFluxJacobian_dRate[NC][1]{}; - real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; - - computeExit ( m_dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - oneSidedFlux, - oneSidedFluxJacobian_dRate, - oneSidedFluxJacobian_dPresCompUp ); - - - globalIndex oneSidedEqnRowIndices[NC]{}; - globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; - globalIndex oneSidedDofColIndices_dRate = 0; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - oneSidedEqnRowIndices[ic] = offsetUp + ROFFSET::MASSBAL + ic - m_rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - oneSidedDofColIndices_dRate = offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - oneSidedDofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - - if( m_useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); - } - - for( integer i = 0; i < NC; ++i ) - { - if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) + stack.localEnergyFlux[0] = -m_dt * eflux * currentConnRate; + stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt*eflux_dq; + for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { - m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - &oneSidedDofColIndices_dRate, - oneSidedFluxJacobian_dRate[i], - 1 ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - oneSidedDofColIndices_dPresCompUp, - oneSidedFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); + stack.localEnergyFluxJacobian[0][dof] *= -m_dt*currentConnRate; } } - } - else // not an exit connection - { - real64 localFlux[2*NC]{}; - real64 localFluxJacobian_dRate[2*NC][1]{}; - real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; - - compute( m_dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - localFlux, - localFluxJacobian_dRate, - localFluxJacobian_dPresCompUp ); - - - globalIndex eqnRowIndices[2*NC]{}; - globalIndex dofColIndices_dPresCompUp[NC+1]{}; - globalIndex dofColIndices_dRate = 0; - - globalIndex const offsetNext = m_wellElemDofNumber[iwelemNext]; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - eqnRowIndices[TAG::NEXT *NC+ic] = offsetNext + ROFFSET::MASSBAL + ic - m_rankOffset; - eqnRowIndices[TAG::CURRENT *NC+ic] = offsetCurrent + ROFFSET::MASSBAL + ic - m_rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - dofColIndices_dRate = offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - dofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - - if( m_useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); - } - - for( integer i = 0; i < 2*NC; ++i ) + else { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + real64 eflux=0; + real64 eflux_dq=0; + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; + for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) + { + std::cout << " wellflux " << ip << " " << dof << " " << m_phaseEnthalpy[iwelemUp][0][ip] << " " << m_dPhaseFraction[iwelemUp][0][ip][dof] + << " " << m_dPhaseEnthalpy[iwelemUp][0][ip][dof] << " " << m_phaseFraction[iwelemUp][0][ip] << std::endl; + stack.localEnergyFluxJacobian[TAG::NEXT ][dof] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][dof] + + m_dPhaseEnthalpy[iwelemUp][0][ip][dof]*m_phaseFraction[iwelemUp][0][ip]; + stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][dof] + + m_dPhaseEnthalpy[iwelemUp][0][ip][dof]*m_phaseFraction[iwelemUp][0][ip]; + } + } + stack.localEnergyFlux[TAG::NEXT ] = m_dt * eflux * currentConnRate; + stack.localEnergyFlux[TAG::CURRENT ] = -m_dt * eflux * currentConnRate; + stack.localEnergyFluxJacobian_dQ [TAG::NEXT ][0] = m_dt * eflux; + stack.localEnergyFluxJacobian_dQ [TAG::CURRENT][0] = -m_dt * eflux; + for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { - m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], - &dofColIndices_dRate, - localFluxJacobian_dRate[i], - 1 ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices_dPresCompUp, - localFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localFlux[i] ); + stack.localEnergyFluxJacobian[TAG::NEXT ][dof] *= m_dt*currentConnRate; + stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] *= -m_dt*currentConnRate; } } - } + + } ); + } @@ -752,7 +923,8 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB * @tparam POLICY the policy used in the RAJA kernels * @tparam KERNEL_TYPE the kernel type * @param[in] numElements the number of elements - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack + * variables */ template< typename POLICY, typename KERNEL_TYPE > static void @@ -762,47 +934,25 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB GEOS_MARK_FUNCTION; forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) { - //typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - // kernelComponent.numPointsInFlux( iconn ) ); + typename KERNEL_TYPE::StackVariables stack( 1 ); - //kernelComponent.setup( iconn, stack ); - kernelComponent.computeFlux( ie ); - //kernelComponent.complete( iconn, stack ); + kernelComponent.setup( ie, stack ); + kernelComponent.computeFlux( ie, stack ); + kernelComponent.complete( ie, stack ); } ); } protected: - /// Time step size - real64 const m_dt; - /// Rank offset for calculating row/col Jacobian indices - integer const m_rankOffset; - - /// Reference to the degree-of-freedom numbers - arrayView1d< globalIndex const > const m_wellElemDofNumber; - /// Next element index, needed since iterating over element nodes, not edges - arrayView1d< localIndex const > const m_nextWellElemIndex; - - /// Connection rate - arrayView1d< real64 const > const m_connRate; - - /// Element component fraction - arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; - /// Element component fraction derivatives - arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + /// Number of phases + integer const m_numPhases; - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - - /// Kernel option flag - integer const m_useTotalMassEquation; - - /// Well type - bool const m_isProducer; + /// Element phase fraction + arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseFraction; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFraction; - /// Injection stream composition - arrayView1d< real64 const > const m_injection; + /// Views on phase enthalpy + arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseEnthalpy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseEnthalpy; }; @@ -836,23 +986,24 @@ class FaceBasedAssemblyKernelFactory string const dofKey, WellControls const & wellControls, ElementSubRegionBase const & subRegion, +MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 2; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); - using kernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF >; + using kernelType = FaceBasedAssemblyKernel< NUM_COMP >; - kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, localMatrix, localRhs, kernelFlags ); + kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, fluid, localMatrix, localRhs, kernelFlags ); kernelType::template launch< POLICY >( subRegion.size(), kernel ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp new file mode 100644 index 00000000000..63747fa5687 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp @@ -0,0 +1,247 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SinglePhaseWellKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALSINGLEPHASEWELLKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALSINGLEPHASEWELLKERNELS_HPP + +#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/wells/WellControls.hpp" +#include "physicsSolvers/SolverBaseKernels.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseWellKernels +{ + + + +/******************************** ElementBasedAssemblyKernel ********************************/ + +/** + * @class ElementBasedAssemblyKernel + * @tparam NUM_DOF number of degrees of freedom + * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance + */ +template< integer NUM_DOF > +class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAssemblyKernel +{ +public: + using Base = singlePhaseWellKernels::ElementBasedAssemblyKernel; + using Base::m_rankOffset; + using Base::m_wellElemDofNumber; + using Base::m_elemGhostRank; + using Base::m_wellElemVolume; + using Base::m_wellElemDensity; + using Base::m_wellElemDensity_n; + using Base::m_dWellElemDensity_dPressure; + using Base::m_localMatrix; + using Base::m_localRhs; + using ROFFSET = singlePhaseWellKernels::RowOffset; + using COFFSET = singlePhaseWellKernels::ColOffset; + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = NUM_DOF; + + /// Compute time value for the number of equations + static constexpr integer numEqn = NUM_DOF; + + /** + * @brief Constructor + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + ElementBasedAssemblyKernel( globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::SingleFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ), + m_dWellElemDensity_dTemperature( fluid.dDensity_dTemperature() ), + m_internalEnergy( fluid.internalEnergy() ), + m_internalEnergy_n( fluid.internalEnergy_n() ), + m_dInternalEnergy_dPres( fluid.dInternalEnergy_dPressure() ), + m_dInternalEnergy_dTemp( fluid.dInternalEnergy_dTemperature() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables : public Base::StackVariables + { +public: + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + {} + using Base::StackVariables::eqnRowIndices; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localJacobian; + using Base::StackVariables::localResidual; + using Base::StackVariables::localRow; + using Base::StackVariables::volume; + using Base::StackVariables::density; + using Base::StackVariables::density_n; + using Base::StackVariables::dDensity_dPres; + + }; + /** + * @brief Getter for the ghost rank of an element + * @param[in] ei the element index + * @return the ghost rank of the element + */ + GEOS_HOST_DEVICE + integer elemGhostRank( localIndex const ei ) const + { return m_elemGhostRank( ei ); } + + + + + /** + * @brief Compute the local accumulation contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the kernel + * @param[in] ei the element index + * @param[inout] stack the stack variables + * @param[in] phaseAmountKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const iwelem, + StackVariables & stack) const + { + Base::computeAccumulation( iwelem, stack, [&]( ) + { + + // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature + stack.localJacobian[0][numDof-1] = stack.volume * m_dWellElemDensity_dTemperature[iwelem][0] ; + + // Step 2: assemble the fluid part of the accumulation term of the energy equation + real64 const fluidEnergy = stack.volume * stack.density * m_internalEnergy[iwelem][0]; + real64 const fluidEnergy_n = stack.volume * stack.density_n * m_internalEnergy_n[iwelem][0]; + + real64 const dFluidEnergy_dP = stack.volume * stack.dDensity_dPres * m_internalEnergy[iwelem][0] + + stack.volume * stack.density * m_dInternalEnergy_dPres[iwelem][0]; + + real64 const dFluidEnergy_dT = stack.volume * m_dWellElemDensity_dTemperature[iwelem][0] * m_internalEnergy[iwelem][0] + + stack.volume * stack.density * m_dInternalEnergy_dTemp[iwelem][0]; + + // local accumulation + stack.localResidual[numEqn-1] = fluidEnergy - fluidEnergy_n; + + // derivatives w.r.t. pressure and temperature + stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; + stack.localJacobian[numEqn-1][numDof-1] = dFluidEnergy_dT; + } ); + } + + + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElems the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) + { + if( kernelComponent.elemGhostRank( iwelem ) >= 0 ) + { + return; + } + typename KERNEL_TYPE::StackVariables stack; + kernelComponent.setup( iwelem, stack ); + kernelComponent.computeAccumulation( iwelem, stack ); + kernelComponent.complete( iwelem, stack ); + + } ); + } + +protected: + + /// View on derivative of fluid density w.r.t temperature + arrayView2d< real64 const > const m_dWellElemDensity_dTemperature; + + /// Views on fluid internal energy + arrayView2d< real64 const > const m_internalEnergy; + arrayView2d< real64 const > const m_internalEnergy_n; + arrayView2d< real64 const > const m_dInternalEnergy_dPres; + arrayView2d< real64 const > const m_dInternalEnergy_dTemp; + +}; + + +/** + * @class ElementBasedAssemblyKernelFactory + */ +class ElementBasedAssemblyKernelFactory +{ +public: + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey the string key to retrieve the degress of freedom numbers + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::SingleFluidBase const & fluid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + integer constexpr NUM_DOF = 2; + ElementBasedAssemblyKernel< NUM_DOF > + kernel( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ); + ElementBasedAssemblyKernel< NUM_DOF >::template + launch< POLICY, ElementBasedAssemblyKernel< NUM_DOF > >( subRegion.size(), kernel ); + + } +}; +} // end namespace singlePhaseWellKernels + +} // end namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELLKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp new file mode 100644 index 00000000000..cefaab8a4ea --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp @@ -0,0 +1,283 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file WellElementKernellUtilities.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLELEMENTKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLELEMENTKERNELS_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" + + + +namespace geos +{ + +namespace wellElementKernelUtilities +{ + +// TODO make input parameter +static constexpr real64 epsC1PPU = 5000; + + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct PotGrad +{ + template< integer NC, integer ISTHERMAL > + GEOS_HOST_DEVICE + static void + compute (real64 const & gravCoef, + real64 const & gravCoefNext, + real64 const & pres, + real64 const & presNext, + real64 const & totalMassDens, + real64 const & totalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, + real64 & potDiff, + real64 ( & dPotDiff)[2][NC+1+IS_THERMAL] ) + + { + // local working variables and arrays + real64 pres[2]{}; + real64 dPres_dP[2]{}; + real64 dPres_dC[2][NC]{}; + real64 dFlux_dP[2]{}; + real64 dFlux_dC[2][NC]{}; + real64 dMult_dP[2]{}; + real64 dMult_dC[2][NC]{}; + real64 dPotDiff_dP[2]{}; + real64 dPotDiff_dC[2][NC]{}; + + real64 multiplier[2]{}; + multiplier[ElemTag::CURRENT] = 1.0; + multiplier[ElemTag::NEXT] = -1.0; + + pres[ElemTag::CURRENT] = pres; + pres[ElemTag::NEXT] = presNext; + + + // local working variables and arrays + real64 dAvgMassDens_dCompCurrent[NC]{}; + real64 dAvgMassDens_dCompNext[NC]{}; + + // compute the average density at the interface between well elements + real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); + + real64 const gravD = gravCoefNext - gravCoef; + pres[0] += + + real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDensNext[Deriv::dP]; + real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens[Deriv::dP]; + for( integer ic = 0; ic < NC; ++ic ) + { + dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDensNext[Deriv::dC+ic]; + dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens[Deriv::dC+ic]; + } + + // compute depth diff times acceleration + real64 const gravD = gravCoefNext - gravCoef; + + potDiff = presNext - pres - avgMassDens * gravD; + + // TODO: add friction and acceleration terms + + /* + localPresRel = ( presNext - pres - avgMassDens * gravD ); + dpot_dp_next = ( 1 - dAvgMassDens_dPresNext * gravD ); + dpot_dp_cur = ( -1 - dAvgMassDens_dPresCurrent * gravD ); + for( integer ic = 0; ic < NC; ++ic ) + { + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; + localPresRelJacobian[TAG::CURRENT *(NC+1) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; + } + if constexpr ( IS_THERMAL ) + { + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDensNext[Deriv::dT]; + localPresRelJacobian[TAG::CURRENT *(NC+1)+1] = 0.5 * dTotalMassDens[Deriv::dT]; + } + */ + } + +}; + + + +struct WellElementPhaseFlux +{ + /** + * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head + * @tparam numComp number of components + * @param numPhase number of phases + * @param ip phase index + * @param pres pressure + * @param gravCoef gravitational coefficient + * @param dPhaseVolFrac derivative of phase volume fraction wrt pressure, temperature, comp density + * @param dCompFrac_dCompDens derivative of component fraction wrt component density + * @param phaseMassDens phase mass density + * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction + * @param potGrad potential gradient for this phase + * @param phaseFlux phase flux + * @param dPhaseFlux derivatives of phase flux + */ + template< integer numComp, integer IS_THERMAL > + GEOS_HOST_DEVICE + static void + compute( integer const ip, + real64 const & gravCoef, + real64 const & gravCoefNext, + real64 const & pres, + real64 const & presNext, + real64 const & totalMassDens, + real64 const & totalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseMassDens, + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dPhaseMassDens, + real64 & potGrad, + real64 ( &phaseFlux ), + real64 ( & dPhaseFlux )[numComp+1+IS_THERMAL] ) + { + real64 dPresGrad_dP[numFluxSupportPoints]{}; + real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; + real64 dGravHead_dP[numFluxSupportPoints]{}; + real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; + PotGrad::compute< numComp, IS_THERMAL >( gravCoef + ,gravCoefNext + , pres + ,presNext + ,totalMassDens + , totalMassDensNext + , dTotalMassDens + , dTotalMassDensNext + , dTotalMassDens_dCompDens + , dTotalMassDens_dCompDensNex ); + + // gravity head + real64 gravHead = gravCoef - gravCoefNext + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + real64 const gravD = trans[i] * gravCoef[er][esr][ei]; + + gravHead += gravD; + } + + // *** upwinding *** + + // phase flux and derivatives + + // assuming TPFA in the code below + + real64 Ttrans = fabs( trans[0] ); + potGrad = potGrad / Ttrans; + + real64 const mobility_i = phaseMob[seri[0]][sesri[0]][sei[0]][ip]; + real64 const mobility_j = phaseMob[seri[1]][sesri[1]][sei[1]][ip]; + + // compute phase flux, see Eqs. (66) and (69) from the reference above + real64 smoEps = epsC1PPU; + if( fabs( gravHead ) <= 1e-20 ) + smoEps = 1000; + real64 const tmpSqrt = sqrt( potGrad * potGrad + smoEps * smoEps ); + real64 const smoMax = 0.5 * (-potGrad + tmpSqrt); + + phaseFlux = potGrad * mobility_i - smoMax * (mobility_j - mobility_i) ); + + // derivativess + + // first part, mobility derivative + + // dP + { + real64 const dMob_dP = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip][Deriv::dP]; + dPhaseFlux_dP[0] += Ttrans * potGrad * dMob_dP; + } + + // dC + { + arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > + dPhaseMobSub = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[0][jc] += Ttrans * potGrad * dPhaseMobSub[Deriv::dC + jc]; + } + } + + real64 const tmpInv = 1.0 / tmpSqrt; + real64 const dSmoMax_x = 0.5 * (1.0 - potGrad * tmpInv); + + // pressure gradient and mobility difference depend on all points in the stencil + real64 const dMobDiff_sign[numFluxSupportPoints] = {-1.0, 1.0}; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + // dP + + real64 const dPotGrad_dP = dPresGrad_dP[ke] - dGravHead_dP[ke]; + + // first part + dPhaseFlux_dP[ke] += dPotGrad_dP * mobility_i; + + // second part + real64 const dSmoMax_dP = -dPotGrad_dP * dSmoMax_x; + dPhaseFlux_dP[ke] += -dSmoMax_dP * (mobility_j - mobility_i); + + real64 const dMob_dP = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dP]; + dPhaseFlux_dP[ke] += -Ttrans * smoMax * dMobDiff_sign[ke] * dMob_dP; + + // dC + + arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > + dPhaseMobSub = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + real64 const dPotGrad_dC = dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; + + // first part + dPhaseFlux_dC[ke][jc] += dPotGrad_dC * mobility_i; + + // second part + real64 const dSmoMax_dC = -dPotGrad_dC * dSmoMax_x; + dPhaseFlux_dC[ke][jc] += -dSmoMax_dC * (mobility_j - mobility_i); + dPhaseFlux_dC[ke][jc] += -Ttrans * smoMax * dMobDiff_sign[ke] * dPhaseMobSub[Deriv::dC + jc]; + } + } + + + } +}; + + +} // namespace wellElementKernelUtilities + +} // namespace geosx + + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLELEMENTKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp new file mode 100644 index 00000000000..2c6549958b0 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellFields.hpp @@ -0,0 +1,59 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file WellFields.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLFIELDS_HPP_ +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLFIELDS_HPP_ + +#include "common/DataLayouts.hpp" +#include "mesh/MeshFields.hpp" + +namespace geos +{ +/** + * A scope for field traits. + */ +namespace fields +{ + +namespace well +{ + +DECLARE_FIELD( energyPerforationFlux, + "energyPerforationFlux", + array1d< real64 >, + 0, + NOPLOT, + WRITE_AND_READ, + "Energy perforation flux" ); + +DECLARE_FIELD( dEnergyPerforationFlux, + "dEnergyPerforationFlux", + array3d< real64 >, + 0, + NOPLOT, + NO_WRITE, + "Derivative of energy perforation flux with respect to pressure temperature and global component density" ); + + +} + +} + +} + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLFIELDS_HPP_ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index c0316d34cb5..e1b2296c801 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -38,12 +38,22 @@ using namespace constitutive; WellSolverBase::WellSolverBase( string const & name, Group * const parent ) : SolverBase( name, parent ), +m_numPhases( 0 ), + m_numComponents( 0 ), m_numDofPerWellElement( 0 ), m_numDofPerResElement( 0 ), m_isThermal( false ), m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" )) { this->getWrapper< string >( viewKeyStruct::discretizationString()).setInputFlag( InputFlags::FALSE ); + + this->registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag indicating whether the problem is thermal or not." ); + + + } Group *WellSolverBase::createChild( string const & childKey, string const & childName ) @@ -72,6 +82,11 @@ void WellSolverBase::postProcessInput() { SolverBase::postProcessInput(); + // 1. Set key dimensions of the problem + m_numDofPerWellElement = m_isThermal ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure connectionRate + temp if thermal + m_numDofPerResElement = m_isThermal ? m_numComponents + 1: m_numComponents; // 1 pressure + temp if thermal + + // create dir for rates output if( getLogLevel() > 0 ) { @@ -88,6 +103,11 @@ void WellSolverBase::registerDataOnMesh( Group & meshBodies ) { SolverBase::registerDataOnMesh( meshBodies ); + //this->registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ). + //setApplyDefaultValue( 0 ). + //setInputFlag( InputFlags::OPTIONAL ). + // setDescription( "Flag indicating whether the problem is thermal or not. Set isThermal=\"1\" to enable the thermal coupling" ); + forDiscretizationOnMeshTargets( meshBodies, [&]( string const &, MeshLevel & meshLevel, arrayView1d< string const > const & regionNames ) @@ -243,11 +263,11 @@ void WellSolverBase::assembleSystem( real64 const time, assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); } - else if( 1 ) + else if( 0 ) { integer const useTotalMassEquation = 1; string const wellDofKey = dofManager.getKey( wellElementDofName()); - if ( 1 ) + if( 1 ) { @@ -265,7 +285,7 @@ void WellSolverBase::assembleSystem( real64 const time, MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); int numPhases = fluid.numFluidPhases(); int numComponents = fluid.numFluidComponents(); - if ( m_isThermal ) + if( m_isThermal ) { thermalCompositionalMultiphaseWellKernels:: @@ -313,7 +333,7 @@ void WellSolverBase::assembleSystem( real64 const time, // then assemble the flux terms in the mass balance equations // get a reference to the degree-of-freedom numbers - if ( 0 ) + if( 0 ) { // then assemble the flux terms in the mass balance equations assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 3724a1e2e81..aa1c7335426 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -101,7 +101,7 @@ class WellSolverBase : public SolverBase * @brief getter for iso/thermal switch * @return True if thermal */ - localIndex isThermal() const { return m_isThermal; } + integer isThermal() const { return m_isThermal; } /** * @brief get the name of DOF defined on well elements @@ -279,6 +279,8 @@ class WellSolverBase : public SolverBase struct viewKeyStruct : SolverBase::viewKeyStruct { static constexpr char const * fluidNamesString() { return "fluidNames"; } +static constexpr char const * isThermalString() { return "isThermal"; } + }; private: @@ -311,6 +313,12 @@ class WellSolverBase : public SolverBase /// name of the flow solver string m_flowSolverName; + /// the max number of fluid phases + integer m_numPhases; + + /// the number of fluid components + integer m_numComponents; + /// the number of Degrees of Freedom per well element integer m_numDofPerWellElement; @@ -322,6 +330,8 @@ class WellSolverBase : public SolverBase string const m_ratesOutputDir; +/// name of the fluid constitutive model used as a reference for component/phase description + string m_referenceFluidModelName; }; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellTags.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellTags.hpp new file mode 100644 index 00000000000..dc75bcbdc9a --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellTags.hpp @@ -0,0 +1,110 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file WellTags.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTAGS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTAGS_HPP + + +namespace geos +{ + +namespace wellTags +{ + +static constexpr real64 minDensForDivision = 1e-10; + +// tag to access well and reservoir elements in perforation rates computation +struct SubRegionTag +{ + static constexpr integer RES = 0; + static constexpr integer WELL = 1; +}; + +// tag to access the next and current well elements of a connection +struct ElemTag +{ + static constexpr integer CURRENT = 0; + static constexpr integer NEXT = 1; +}; + +// define the column offset of the derivatives +struct ColOffset +{ + static constexpr integer DPRES = 0; + static constexpr integer DCOMP = 1; +}; + +template< integer NC, integer IS_THERMAL > +struct ColOffset_WellJac; + +template< integer NC > +struct ColOffset_WellJac< NC, 0 > +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static integer constexpr nDer = dQ + 1; + +}; + +template< integer NC > +struct ColOffset_WellJac< NC, 1 > +{ + static constexpr integer dP = 0; + static constexpr integer dC = 1; + static constexpr integer dQ = dC + NC; + static constexpr integer dT = dQ+1; + /// number of derivatives + static integer constexpr nDer = dT + 1; +}; + +// define the row offset of the residual equations +struct RowOffset +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; +}; + +template< integer NC, integer IS_THERMAL > +struct RowOffset_WellJac; + +template< integer NC > +struct RowOffset_WellJac< NC, 0 > +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer nEqn = VOLBAL+1; +}; + +template< integer NC > +struct RowOffset_WellJac< NC, 1 > +{ + static constexpr integer CONTROL = 0; + static constexpr integer MASSBAL = 1; + static constexpr integer VOLBAL = MASSBAL + NC; + static constexpr integer ENERGYBAL = VOLBAL+1; + static constexpr integer nEqn = ENERGYBAL+1; + +}; + +} // end namespace wellTags + +} // end namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTAGS_HPP diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index ef75ab18317..61578478a34 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -30,6 +30,7 @@ #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/multiphysics/MultiphasePoromechanics.hpp" +#include "physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp" namespace geos { @@ -179,7 +180,7 @@ addCouplingSparsityPattern( DomainPartition const & domain, integer const wellNDOF = Base::wellSolver()->numDofPerWellElement(); integer constexpr maxNumComp = MultiFluidBase::MAX_NUM_COMPONENTS; - integer constexpr maxNumDof = maxNumComp + 1; + integer constexpr maxNumDof = maxNumComp + 2; string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); string const resDofKey = dofManager.getKey( Base::wellSolver()->resElementDofName() ); @@ -293,7 +294,7 @@ assembleCouplingTerms( real64 const time_n, ElementRegionManager const & elemManager = mesh.getElemManager(); integer constexpr MAX_NUM_COMP = MultiFluidBase::MAX_NUM_COMPONENTS; - integer constexpr MAX_NUM_DOF = MAX_NUM_COMP + 1; + integer constexpr MAX_NUM_DOF = MAX_NUM_COMP + 2; integer const numComps = Base::wellSolver()->numFluidComponents(); integer const resNumDofs = Base::wellSolver()->numDofPerResElement(); @@ -308,6 +309,8 @@ assembleCouplingTerms( real64 const time_n, elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion const & subRegion ) { +string const & fluidName = this->flowSolver()->template getConstitutiveName< MultiFluidBase >( subRegion ); + MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); // if the well is shut, we neglect reservoir-well flow that may occur despite the zero rate // therefore, we do not want to compute perforation rates and we simply assume they are zero @@ -321,12 +324,19 @@ assembleCouplingTerms( real64 const time_n, return; } - areWellsShut = 0; - PerforationData const * const perforationData = subRegion.getPerforationData(); // get the degrees of freedom string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); +areWellsShut = 0; + + if( 1 ) + { + + + + RAJA::ReduceSum< parallelDeviceReduce, integer > numCrossflowPerforations( 0 ); + arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey ); @@ -337,7 +347,8 @@ assembleCouplingTerms( real64 const time_n, perforationData->getField< fields::well::dCompPerforationRate_dPres >(); arrayView4d< real64 const > const & dCompPerfRate_dComp = perforationData->getField< fields::well::dCompPerforationRate_dComp >(); - +arrayView4d< real64 const > const & dCompPerfRate = + perforationData->getField< fields::well::dCompPerforationRate >(); arrayView1d< localIndex const > const & perfWellElemIndex = perforationData->getField< fields::perforation::wellElementIndex >(); @@ -349,10 +360,9 @@ assembleCouplingTerms( real64 const time_n, arrayView1d< localIndex const > const & resElementIndex = perforationData->getField< fields::perforation::reservoirElementIndex >(); - bool const useTotalMassEquation = this->flowSolver()->useTotalMassEquation() > 0; - - RAJA::ReduceSum< parallelDeviceReduce, integer > numCrossflowPerforations( 0 ); + integer const useTotalMassEquation = this->flowSolver()->useTotalMassEquation(); + // loop over the perforations and add the rates to the residual and jacobian forAll< parallelDevicePolicy<> >( perforationData->size(), [=] GEOS_HOST_DEVICE ( localIndex const iperf ) { @@ -401,12 +411,14 @@ assembleCouplingTerms( real64 const time_n, for( integer ke = 0; ke < 2; ++ke ) { localIndex const localDofIndexPres = ke * resNumDofs; + localPerfJacobian[TAG::RES * numComps + ic][localDofIndexPres] = dt * dCompPerfRate_dPres[iperf][ke][ic]; localPerfJacobian[TAG::WELL * numComps + ic][localDofIndexPres] = -dt * dCompPerfRate_dPres[iperf][ke][ic]; for( integer jc = 0; jc < numComps; ++jc ) { localIndex const localDofIndexComp = localDofIndexPres + jc + 1; +//assert( fabs( dCompPerfRate_dComp[iperf][ke][ic][jc] -dCompPerfRate[iperf][ke][ic][jc] ) < FLT_EPSILON ); localPerfJacobian[TAG::RES * numComps + ic][localDofIndexComp] = dt * dCompPerfRate_dComp[iperf][ke][ic][jc]; localPerfJacobian[TAG::WELL * numComps + ic][localDofIndexComp] = -dt * dCompPerfRate_dComp[iperf][ke][ic][jc]; } @@ -429,13 +441,15 @@ assembleCouplingTerms( real64 const time_n, dofColIndices.data(), localPerfJacobian[i].dataIfContiguous(), 2 * resNumDofs ); +std::cout << " coupled R&W perf " << i << " " << eqnRowIndices[i] << " " << localPerf[i] << " " << localRhs[eqnRowIndices[i]] << std::endl; RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndices[i]], localPerf[i] ); } } } ); - if( detectCrossflow ) // check to avoid communications if not needed + + if( detectCrossflow ) // check to avoid communications if not needed { globalIndex const totalNumCrossflowPerforations = MpiWrapper::sum( numCrossflowPerforations.get() ); if( totalNumCrossflowPerforations > 0 ) @@ -446,12 +460,66 @@ assembleCouplingTerms( real64 const time_n, WellControls::viewKeyStruct::enableCrossflowString(), wellControls.getName() ) ); } } - } ); + + } + else + { + integer useTotalMassEquation1=1; + integer numCrossflowPerforations=0; + if( isThermal ( ) ) + { + coupledReservoirAndWellKernels:: + ThermalCompositionalMultiPhaseFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComps, + dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + useTotalMassEquation1, + detectCrossflow, + numCrossflowPerforations, + localRhs, + localMatrix ); + } + else + { + coupledReservoirAndWellKernels:: + IsothermalCompositionalMultiPhaseFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComps, + dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + useTotalMassEquation1, + detectCrossflow, + numCrossflowPerforations, + localRhs, + localMatrix ); + } + + if( detectCrossflow ) // check to avoid communications if not needed + { + globalIndex const totalNumCrossflowPerforations = MpiWrapper::sum( numCrossflowPerforations ); + if( totalNumCrossflowPerforations > 0 ) + { + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "CompositionalMultiphaseReservoir '{}': Warning! Crossflow detected at {} perforations in well {}" + "To disable crossflow for injectors, you can use the field '{}' in the WellControls '{}' section", + this->getName(), totalNumCrossflowPerforations, subRegion.getName(), + WellControls::viewKeyStruct::enableCrossflowString(), wellControls.getName() ) ); + } + } + } // update dynamically the MGR recipe to optimize the linear solve if all wells are shut areWellsShut = MpiWrapper::min( areWellsShut ); m_linearSolverParameters.get().mgr.areWellsShut = areWellsShut; - +} ); } ); } diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp new file mode 100644 index 00000000000..4a563662a10 --- /dev/null +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -0,0 +1,604 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalCompositionalMultiphaseWellKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLS_HPP +#define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLS_HPP + + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/SolverBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellTags.hpp" +#include "physicsSolvers/fluidFlow/wells/WellFields.hpp" +namespace geos +{ + +namespace coupledReservoirAndWellKernels +{ + +using namespace constitutive; + +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NC , integer IS_THERMAL > +class IsothermalCompositionalMultiPhaseFluxKernel +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NC; + static constexpr integer resNumDOF = NC+1+IS_THERMAL; + + // Well jacobian column and row indicies + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + + using TAG = compositionalMultiphaseWellKernels::SubRegionTag; + + + + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = WJ_COFFSET::nDer; + + /// Compile time value for the number of equations except volume and momentum + static constexpr integer numEqn = WJ_ROFFSET::nEqn - 2; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + IsothermalCompositionalMultiPhaseFluxKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + bool const & detectCrossflow , + integer & numCrossFlowPerforations, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + : + m_dt( dt ), + m_numPhases ( fluid.numFluidPhases()), + m_rankOffset(rankOffset), + m_compPerfRate( perforationData->getField< fields::well::compPerforationRate >() ), + m_dCompPerfRate_dPres( perforationData->getField< fields::well::dCompPerforationRate_dPres >() ), + m_dCompPerfRate_dComp( perforationData->getField< fields::well::dCompPerforationRate_dComp >() ), + m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate>() ), + m_perfWellElemIndex( perforationData->getField< fields::perforation::wellElementIndex >() ), + m_wellElemDofNumber( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), + m_resElemDofNumber( resDofNumber ), + m_resElementRegion( perforationData->getField< fields::perforation::reservoirElementRegion >() ), + m_resElementSubRegion( perforationData->getField< fields::perforation::reservoirElementSubRegion >() ), + m_resElementIndex( perforationData->getField< fields::perforation::reservoirElementIndex >() ), + m_localRhs( localRhs ), + m_localMatrix( localMatrix ), + m_detectCrossflow( detectCrossflow ), + m_numCrossFlowPerforations( numCrossFlowPerforations ), + m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) + { } + + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iperf, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + using namespace compositionalMultiphaseUtilities; + // local working variables and arrays + stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 * numComp ); + stackArray1d< globalIndex, 2*resNumDOF > dofColIndices( 2 * resNumDOF ); + + stackArray1d< real64, 2 * numComp > localPerf( 2 * numComp ); + stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2 * numComp, 2 * resNumDOF ); + + // get the reservoir (sub)region and element indices + localIndex const er = m_resElementRegion[iperf]; + localIndex const esr = m_resElementSubRegion[iperf]; + localIndex const ei = m_resElementIndex[iperf]; + + // get the well element index for this perforation + localIndex const iwelem = m_perfWellElemIndex[iperf]; + globalIndex const resOffset = m_resElemDofNumber[er][esr][ei]; + globalIndex const wellElemOffset = m_wellElemDofNumber[iwelem]; + + for( integer ic = 0; ic < numComp; ++ic ) + { + eqnRowIndices[TAG::RES * numComp + ic] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + ic; + eqnRowIndices[TAG::WELL * numComp + ic] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::MASSBAL + ic; + } + // Note res and well have same col lineup for P and compdens + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + dofColIndices[TAG::RES * resNumDOF + jdof] = resOffset + jdof; + dofColIndices[TAG::WELL * resNumDOF + jdof] = wellElemOffset + COFFSET::DPRES + jdof; + } + // For temp its different + if constexpr ( IS_THERMAL ) + { + dofColIndices[TAG::RES * resNumDOF + NC+1 ] = resOffset + NC+1; + dofColIndices[TAG::WELL * resNumDOF + NC+1 ] = wellElemOffset + CP_Deriv::dT; + } + // populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + localPerf[TAG::RES * numComp + ic] = m_dt * m_compPerfRate[iperf][ic]; + localPerf[TAG::WELL * numComp + ic] = -m_dt * m_compPerfRate[iperf][ic]; + + if( m_detectCrossflow ) + { + if( m_compPerfRate[iperf][ic] > LvArray::NumericLimits< real64 >::epsilon ) + { + m_numCrossFlowPerforations += 1; + } + } + if ( 1 ) + { + + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const localDofIndexPres = ke * resNumDOF; + + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexPres] = m_dt * m_dCompPerfRate_dPres[iperf][ke][ic]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexPres] = -m_dt * m_dCompPerfRate_dPres[iperf][ke][ic]; + assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP] - m_dCompPerfRate_dPres[iperf][ke][ic] ) < FLT_EPSILON ); + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] - m_dCompPerfRate_dComp[iperf][ke][ic][jc] ) < FLT_EPSILON ); + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate_dComp[iperf][ke][ic][jc]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate_dComp[iperf][ke][ic][jc]; + } + } + } + else + { + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex localDofIndexPres = ke * resNumDOF; + + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexPres] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexPres] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; + assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP] - m_dCompPerfRate_dPres[iperf][ke][ic] ) < FLT_EPSILON ); + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] - m_dCompPerfRate_dComp[iperf][ke][ic][jc] ) < FLT_EPSILON ); + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] ; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] ; + } + if constexpr ( IS_THERMAL ) + { + localIndex localDofIndexTemp = localDofIndexPres + NC + 1; + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexTemp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexTemp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; + } + } + } + } + + if( m_useTotalMassEquation ) + { + // Apply equation/variable change transformation(s) + stackArray1d< real64, 2 * resNumDOF > work( 2 * resNumDOF ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp, resNumDOF * 2, 2, localPerfJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numComp, 2, localPerf ); + } + + for( localIndex i = 0; i < localPerf.size(); ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices.data(), + localPerfJacobian[i].dataIfContiguous(), + 2 * resNumDOF ); + std::cout << " coupled R&W perf " << i << " " << eqnRowIndices[i] << " " << localPerf[i] << " " << m_localRhs[eqnRowIndices[i]] << std::endl; + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); + } + } + compFluxKernelOp( resOffset, wellElemOffset, dofColIndices ); + + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack + * variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + kernelComponent.computeFlux( ie); + + } ); + } + +protected: + + /// Time step size + real64 const m_dt; + + /// Number of phases + integer const m_numPhases; + + globalIndex const m_rankOffset; + // Perfoation variables + arrayView2d< real64 const > const m_compPerfRate; + arrayView3d< real64 const > const m_dCompPerfRate_dPres; + arrayView4d< real64 const > const m_dCompPerfRate_dComp; + arrayView4d< real64 const > const m_dCompPerfRate; + arrayView1d< localIndex const > const m_perfWellElemIndex; + + // Element region, subregion, index + arrayView1d< globalIndex const > const m_wellElemDofNumber; + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const m_resElemDofNumber; + arrayView1d< localIndex const > const m_resElementRegion; + arrayView1d< localIndex const > const m_resElementSubRegion; + arrayView1d< localIndex const > const m_resElementIndex; + + // RHS and Jacobian + arrayView1d< real64 > const m_localRhs; + CRSMatrixView< real64, globalIndex const > m_localMatrix; + + bool const m_detectCrossflow; + integer & m_numCrossFlowPerforations; + integer const m_useTotalMassEquation; +}; + +/** + * @class FaceBasedAssemblyKernelFactory + */ +class IsothermalCompositionalMultiPhaseFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + integer const & useTotalMassEquation, + bool const & detectCrossflow , + integer & numCrossFlowPerforations, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix + ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + + + using kernelType = IsothermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 0 >; + + + kernelType kernel( dt, rankOffset, wellDofKey, subRegion,resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + + } +}; + + +/** + * @class FaceBasedAssemblyKernel + * @tparam NUM_COMP number of fluid components + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NC , integer IS_THERMAL > +class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalMultiPhaseFluxKernel +{ +public: + using Base = IsothermalCompositionalMultiPhaseFluxKernel< NC, IS_THERMAL >; + /// Compile time value for the number of components + static constexpr integer numComp = NC; + static constexpr integer resNumDOF = NC+1+IS_THERMAL; + + // Well jacobian column and row indicies + using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; + using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; + + using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; + using COFFSET = compositionalMultiphaseWellKernels::ColOffset; + + using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + + using TAG = compositionalMultiphaseWellKernels::SubRegionTag; + + using Base::m_dt; + using Base::m_localRhs; + using Base::m_localMatrix; + using Base::m_rankOffset; + + + + + /// Compute time value for the number of degrees of freedom + static constexpr integer numDof = WJ_COFFSET::nDer; + + /// Compile time value for the number of equations except volume and momentum + static constexpr integer numEqn = WJ_ROFFSET::nEqn - 2; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor + * @param[in] compFlowAccessors + * @param[in] multiFluidAccessors + * @param[in] capPressureAccessors + * @param[in] permeabilityAccessors + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + * @param[in] kernelFlags flags packed together + */ + ThermalCompositionalMultiPhaseFluxKernel( real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + bool const & detectCrossflow , + integer & numCrossFlowPerforations, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + : Base( dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + localRhs, + localMatrix, + detectCrossflow , + numCrossFlowPerforations, + kernelFlags ), + m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()) , + m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) + + { } + + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes + * @param[in] ie the element index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iperf ) const + { + Base::computeFlux( iperf ,[&] (globalIndex const & resOffset , + globalIndex const & wellElemOffset, + stackArray1d< globalIndex, 2*resNumDOF >& dofColIndices ) + { + // local working variables and arrays + stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 ); + + stackArray1d< real64, 2 * numComp > localPerf( 2 ); + stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2 , 2 * resNumDOF ); + + + // equantion offsets - note res and well have different equation lineups + eqnRowIndices[TAG::RES ] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + NC + 1; + eqnRowIndices[TAG::WELL ] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::ENERGYBAL; + + // populate local flux vector and derivatives + localPerf[TAG::RES ] = m_dt * m_energyPerfFlux[iperf]; + localPerf[TAG::WELL ] = -m_dt * m_energyPerfFlux[iperf]; + + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex localDofIndexPres = ke * resNumDOF; + localPerfJacobian[TAG::RES ][localDofIndexPres] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; + localPerfJacobian[TAG::WELL ][localDofIndexPres] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; + localDofIndexPres += 1; + // populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + localIndex const localDofIndexComp = localDofIndexPres + ic + 1; + localPerfJacobian[TAG::RES ][localDofIndexComp] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic] ; + localPerfJacobian[TAG::WELL][localDofIndexComp] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic] ; + } + localPerfJacobian[TAG::RES ][localDofIndexPres+NC+1] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT] ; + localPerfJacobian[TAG::WELL][localDofIndexPres+NC+1] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT] ; + } + + + for( localIndex i = 0; i < localPerf.size(); ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices.data(), + localPerfJacobian[i].dataIfContiguous(), + 2 * resNumDOF ); + std::cout << " coupled R&W perf " << i << " " << eqnRowIndices[i] << " " << localPerf[i] << " " << m_localRhs[eqnRowIndices[i]] << std::endl; + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); + } + } + }); + + + } + + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numElements the number of elements + * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack + * variables + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElements, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) + { + kernelComponent.computeFlux( ie); + + } ); + } + +protected: + + /// Views on energy flux + arrayView1d< real64 const > const m_energyPerfFlux; + arrayView3d< real64 const > const m_dEnergyPerfFlux; +}; + +/** + * @class ThermalCompositionalMultiPhaseFluxKernelFactory + */ +class ThermalCompositionalMultiPhaseFluxKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] numComps the number of fluid components + * @param[in] dt time step size + * @param[in] rankOffset the offset of my MPI rank + * @param[in] useTotalMassEquation flag specifying whether to replace one component bal eqn with total mass eqn + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] wellControls object holding well control/constraint information + * @param[in] subregion well subregion + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComps, + real64 const dt, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + integer const & useTotalMassEquation, + bool const & detectCrossflow , + integer & numCrossFlowPerforations, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix + ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) + { + integer constexpr NUM_COMP = NC(); + + + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + + + using kernelType = ThermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 1 >; + + + kernelType kernel( dt, rankOffset, wellDofKey, subRegion,resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); + + } +}; + +}; // end namespace coupledReservoirAndWellKernels + +} // end namespace geos + +#endif // GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLS_HPP diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp index 871982d3787..781fcade5ca 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp @@ -20,6 +20,7 @@ #include "SinglePhaseReservoirAndWells.hpp" #include "common/TimingMacros.hpp" +#include "common/KernelLaunchSelectors.hpp" #include "mesh/PerforationFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseFVM.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" @@ -162,14 +163,15 @@ addCouplingSparsityPattern( DomainPartition const & domain, string const resDofKey = dofManager.getKey( Base::wellSolver()->resElementDofName() ); string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); - +integer isThermal = Base::wellSolver()->isThermal(); integer const wellNDOF = Base::wellSolver()->numDofPerWellElement(); ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > const & resDofNumber = elemManager.constructArrayViewAccessor< globalIndex, 1 >( resDofKey ); globalIndex const rankOffset = dofManager.rankOffset(); - +geos::internal::kernelLaunchSelectorThermalSwitch( isThermal, [&] ( auto ISTHERMAL ) { + integer constexpr IS_THERMAL = ISTHERMAL(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion const & subRegion ) { @@ -204,9 +206,9 @@ addCouplingSparsityPattern( DomainPartition const & domain, globalIndex const eqnRowIndexRes = resDofNumber[er][esr][ei] - rankOffset; globalIndex const dofColIndexRes = resDofNumber[er][esr][ei]; - // working arrays - stackArray1d< globalIndex, 2 > eqnRowIndicesWell( wellNDOF ); - stackArray1d< globalIndex, 2 > dofColIndicesWell( wellNDOF ); + // working arrays - tjb previously dim was 2 + stackArray1d< globalIndex, 2+IS_THERMAL > eqnRowIndicesWell( wellNDOF ); + stackArray1d< globalIndex, 2+IS_THERMAL > dofColIndicesWell( wellNDOF ); for( integer idof = 0; idof < wellNDOF; ++idof ) { @@ -232,6 +234,7 @@ addCouplingSparsityPattern( DomainPartition const & domain, } ); } ); } ); +} ); } template< typename SINGLEPHASE_RESERVOIR_SOLVER > From 6323c13833fca9b7030304d2f3e97ac48c4b854b Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:35:34 -0700 Subject: [PATCH 12/71] 1) fix isthermal well field runtime error 2) fix refactored isothermal flux index bug 3) 2 isothermal models tested with refactored code 4) thermal case crashes at 2nd linear solve well internal energy derivative = 0 --- .../wells/CompositionalMultiphaseWell.cpp | 18 +++++++++++++++--- .../wells/CompositionalMultiphaseWell.hpp | 4 ++-- .../CompositionalMultiphaseWellKernels.hpp | 11 ++++------- ...ermalCompositionalMultiphaseWellKernels.hpp | 2 +- .../fluidFlow/wells/WellSolverBase.cpp | 2 +- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index c78711b525d..5db9ddf7bbf 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1006,7 +1006,7 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & fluid ); } -void CompositionalMultiphaseWell::assembleSystem1( real64 const time, +void CompositionalMultiphaseWell::assembleSystem( real64 const time, real64 const dt, DomainPartition & domain, DofManager const & dofManager, @@ -1015,7 +1015,7 @@ void CompositionalMultiphaseWell::assembleSystem1( real64 const time, { integer const useTotalMassEquation = 1; string const wellDofKey = dofManager.getKey( wellElementDofName()); - if( 0 ) + if( 1 ) { forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, @@ -1078,7 +1078,7 @@ void CompositionalMultiphaseWell::assembleSystem1( real64 const time, // then assemble the flux terms in the mass balance equations // get a reference to the degree-of-freedom numbers - if( 1 ) + if( 0 ) { // then assemble the flux terms in the mass balance equations assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); @@ -1517,6 +1517,9 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, DofManager const & dofManager, arrayView1d< real64 const > const & localRhs ) { + + return calculateResidualNorm1( time_n, dt, domain, dofManager, localRhs); + GEOS_MARK_FUNCTION; real64 localResidualNorm = 0.0; @@ -1950,6 +1953,15 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & subRegion.getField< fields::well::pressure_n >(); wellElemPressure.setValues< parallelDevicePolicy<> >( wellElemPressure_n ); +if ( isThermal() ) + { + // get a reference to the primary variables on well elements + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + arrayView1d< real64 const > const & wellElemTemperature_n = + subRegion.getField< fields::well::temperature_n >(); + wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n ); + } arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity = subRegion.getField< fields::well::globalCompDensity >(); arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity_n = diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index dac396dca3d..54061cb2b55 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -200,12 +200,12 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual localIndex numFluidPhases() const override { return m_numPhases; } -virtual void assembleSystem1( real64 const time, +virtual void assembleSystem( real64 const time, real64 const dt, DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the flux terms for all connections between well elements * @param time_n previous time value diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 466471040c9..559363546a8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -1090,7 +1090,7 @@ class ElementBasedAssemblyKernel /// Compile time value for the number of components static constexpr integer numComp = NUM_COMP; - /// Number of Dof's set in this kernal + /// Number of Dof's set in this kernal - no dQ in accum static constexpr integer numDof = NUM_COMP + 1 + IS_THERMAL; /// Compute time value for the number of equations @@ -1412,12 +1412,7 @@ if constexpr ( IS_THERMAL ) // apply equation/variable change transformation to the component mass balance equations real64 work[numComp + 1 + IS_THERMAL]{}; shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp+1+ IS_THERMAL, stack.localJacobian, work ); -for( integer i=0; i= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) { +std::cout << i << " " << eqnRowIndices[i] << " " << dofColIndices_dRate << std::endl; + std::cout.flush(); m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], &dofColIndices_dRate, localFluxJacobian_dRate[i], @@ -2533,7 +2530,7 @@ class FaceBasedAssemblyKernel stack, dCompFlux ); - +stack.offsetNext = m_wellElemDofNumber[iwelemNext]; /* globalIndex eqnRowIndices[2*NC]{}; globalIndex dofColIndices_dPresCompUp[NC+1]{}; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index e459b685117..16b920c5a29 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -580,7 +580,7 @@ std::cout << "wellthermaccum " << ip << " " << dPhaseAmount[FLUID_PROP_COFFSET:: // derivatives w.r.t. pressure and temperature stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP; stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; -std::cout << " ip " << ip << " " << stack.localJacobian[numEqn-1][0] << " " << stack.localJacobian[numEqn-1][numDof-1] << std::endl; +std::cout << "dPhaseEnergy ip " << ip << " dp " << stack.localJacobian[numEqn-1][0] << " dt " << stack.localJacobian[numEqn-1][numDof-1] << std::endl; // derivatives w.r.t. component densities applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index e1b2296c801..9e57353d8a7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -47,7 +47,7 @@ m_numPhases( 0 ), { this->getWrapper< string >( viewKeyStruct::discretizationString()).setInputFlag( InputFlags::FALSE ); - this->registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ). + registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Flag indicating whether the problem is thermal or not." ); From 34a2a01a6e84d33ce27aa6f096d61598a70b5ba4 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:17:51 -0700 Subject: [PATCH 13/71] thermal well devs - 1) derivative bugfixes 2) added thermal to post linear solve well methods 3) next step verify simple test case results --- .../wells/CompositionalMultiphaseWell.cpp | 21 ++++++++++++-- .../wells/PerforationFluxKernels.hpp | 29 +++++++++++++------ ...rmalCompositionalMultiphaseWellKernels.hpp | 7 +++-- ...mpositionalMultiphaseReservoirAndWells.cpp | 2 +- .../CoupledReservoirAndWellKernels.hpp | 6 ++-- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 5db9ddf7bbf..aff0b356153 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1879,12 +1879,21 @@ if( isThermal() ) { // synchronize FieldIdentifiers fieldsToBeSync; - +if ( isThermal() ) + { fieldsToBeSync.addElementFields( { fields::well::pressure::key(), +fields::well::temperature::key(), fields::well::globalCompDensity::key(), fields::well::mixtureConnectionRate::key() }, regionNames ); - +} + else + { + fieldsToBeSync.addElementFields( { fields::well::pressure::key(), + fields::well::globalCompDensity::key(), + fields::well::mixtureConnectionRate::key() }, + regionNames ); + } CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, domain.getNeighbors(), @@ -2202,6 +2211,14 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, subRegion.getField< fields::well::pressure_n >(); wellElemPressure_n.setValues< parallelDevicePolicy<> >( wellElemPressure ); +if ( isThermal() ) + { + arrayView1d< real64 const > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + arrayView1d< real64 > const & wellElemTemperature_n = + subRegion.getField< fields::well::temperature_n >(); + wellElemTemperature_n.setValues< parallelDevicePolicy<> >( wellElemTemperature ); + } arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity = subRegion.getField< fields::well::globalCompDensity >(); arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity_n = diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index 93e22e4cb5d..1d643ecf0b2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -263,7 +263,7 @@ struct StackVariables real64 const gravD = ( m_perfGravCoef[iperf] - m_wellElemGravCoef[iwelem] ); pres[TAG::WELL] += m_wellElemTotalMassDens[iwelem] * gravD; - // Note RHS uses CP_Deriv while LHS uses Deriv !!! + // Note LHS uses CP_Deriv while RHS uses Deriv !!! dPres_dP[TAG::WELL] += m_dWellElemTotalMassDens_dPres[iwelem] * gravD; dPres[TAG::WELL][CP_Deriv::dP] += m_dWellElemTotalMassDens_dPres[iwelem] * gravD; if constexpr ( IS_THERMAL ) @@ -475,7 +475,7 @@ struct StackVariables flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; // energy equation derivatives WRT well P stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * res_enthalpy ; - // stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * res_enthalpy ; + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * res_enthalpy ; // energy equation derivatives WRT reservoir dens real64 dProp_dC[numComp]{}; @@ -675,17 +675,22 @@ struct StackVariables { for( integer ip = 0; ip < NP; ++ip ) { +bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; + if ( ! phaseExists ) + continue; + double pflux = stack.m_wellElemPhaseVolFrac[iwelem][ip]*flux; real64 const wellelem_enthalpy = stack.m_wellElemPhaseEnthalpy[iwelem][0][ip]; - stack.m_energyPerfFlux[iperf] += flux * wellelem_enthalpy; + stack.m_energyPerfFlux[iperf] += pflux * wellelem_enthalpy; // energy equation derivatives WRT res P & T stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy ; stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy ; // energy equation derivatives WRT well P & T stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy - + flux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dP]; + + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dP] + + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][CP_Deriv::dP]; stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy - + flux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dT]; - + + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dT] + + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][CP_Deriv::dT]; // energy equation derivatives WRT reservoir dens real64 dProp_dC[numComp]{}; applyChainRule( NC, @@ -903,7 +908,8 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati multiFluidAccessors, relPermAccessors, disableReservoirToWellFlow ), - m_stack(perforationData, + m_stack(subRegion, + perforationData, fluid, thermalCompFlowAccessors, thermalMultiFluidAccessors) @@ -924,11 +930,14 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati public: GEOS_HOST_DEVICE - StackVariables( PerforationData * const perforationData, + StackVariables( ElementSubRegionBase const & subRegion, + PerforationData * const perforationData, MultiFluidBase const & fluid, ThermalCompFlowAccessors const & thermalCompFlowAccessors, ThermalMultiFluidAccessors const & thermalMultiFluidAccessors ) : Base::StackVariables(), +m_wellElemPhaseVolFrac(subRegion.getField< fields::well::phaseVolumeFraction >()), + m_dPhaseVolFrac( subRegion.getField< fields::well::dPhaseVolumeFraction >() ), m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()) , @@ -938,7 +947,9 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) {} - /// Views on phase enthalpy + /// Views on well element properties + arrayView2d< real64 const, compflow::USD_PHASE > m_wellElemPhaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 16b920c5a29..bd625b2a2e5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -881,7 +881,7 @@ struct StackVariables : public Base::StackVariables stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt*eflux_dq; for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { - stack.localEnergyFluxJacobian[0][dof] *= -m_dt*currentConnRate; + stack.localEnergyFluxJacobian[0][dof] = -m_dt*currentConnRate; } } else @@ -904,12 +904,13 @@ struct StackVariables : public Base::StackVariables } stack.localEnergyFlux[TAG::NEXT ] = m_dt * eflux * currentConnRate; stack.localEnergyFlux[TAG::CURRENT ] = -m_dt * eflux * currentConnRate; + stack.localEnergyFluxJacobian_dQ [TAG::NEXT ][0] = m_dt * eflux; stack.localEnergyFluxJacobian_dQ [TAG::CURRENT][0] = -m_dt * eflux; for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { - stack.localEnergyFluxJacobian[TAG::NEXT ][dof] *= m_dt*currentConnRate; - stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] *= -m_dt*currentConnRate; + stack.localEnergyFluxJacobian[TAG::NEXT ][dof] = m_dt*currentConnRate; + stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] = -m_dt*currentConnRate; } } diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index 61578478a34..109543d0b8c 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -330,7 +330,7 @@ string const & fluidName = this->flowSolver()->template getConstitutiveName< Mul string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); areWellsShut = 0; - if( 1 ) + if( 0 ) { diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 4a563662a10..e4de48fa9ef 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -160,13 +160,13 @@ class IsothermalCompositionalMultiPhaseFluxKernel for( integer jdof = 0; jdof < NC+1; ++jdof ) { dofColIndices[TAG::RES * resNumDOF + jdof] = resOffset + jdof; - dofColIndices[TAG::WELL * resNumDOF + jdof] = wellElemOffset + COFFSET::DPRES + jdof; + dofColIndices[TAG::WELL * resNumDOF + jdof] = wellElemOffset + WJ_COFFSET::dP + jdof; } // For temp its different if constexpr ( IS_THERMAL ) { dofColIndices[TAG::RES * resNumDOF + NC+1 ] = resOffset + NC+1; - dofColIndices[TAG::WELL * resNumDOF + NC+1 ] = wellElemOffset + CP_Deriv::dT; + dofColIndices[TAG::WELL * resNumDOF + NC+1 ] = wellElemOffset + WJ_COFFSET::dT; } // populate local flux vector and derivatives for( integer ic = 0; ic < numComp; ++ic ) @@ -481,7 +481,7 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional localIndex localDofIndexPres = ke * resNumDOF; localPerfJacobian[TAG::RES ][localDofIndexPres] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; localPerfJacobian[TAG::WELL ][localDofIndexPres] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; - localDofIndexPres += 1; + //localDofIndexPres += 1; // populate local flux vector and derivatives for( integer ic = 0; ic < numComp; ++ic ) { From 828b0095ba67f7ffd2b460b92897e48dab2a3bdb Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 1 May 2024 09:22:36 -0700 Subject: [PATCH 14/71] thermal devs - 1) fixes for > 1 well seg 2) added soln updating/scaling 3) removed debug std::couts 4) next steps a) address constant temp BC b) singlephase thermo dev c) deriv checker --- .../common/KernelLaunchSelectors.hpp | 9 +- .../multifluid/CO2Brine/CO2BrineFluid.hpp | 1 - .../mesh/ElementRegionManager.hpp | 2 - .../fluidFlow/CompositionalMultiphaseBase.cpp | 3 - .../fluidFlow/CompositionalMultiphaseFVM.cpp | 48 +- .../CompositionalMultiphaseHybridFVM.cpp | 25 + ...rmalCompositionalMultiphaseBaseKernels.hpp | 43 +- ...rmalCompositionalMultiphaseBaseKernels.hpp | 90 ++-- .../wells/CompositionalMultiphaseWell.cpp | 259 +++++++++- .../wells/CompositionalMultiphaseWell.hpp | 5 + .../CompositionalMultiphaseWellKernels.cpp | 27 +- .../CompositionalMultiphaseWellKernels.hpp | 445 +----------------- .../wells/PerforationFluxKernels.hpp | 168 +++---- ...rmalCompositionalMultiphaseWellKernels.hpp | 69 ++- .../wells/ThermalSinglePhaseWellKernels.hpp | 16 +- .../wells/WellElementKernelUtilities.hpp | 8 +- .../fluidFlow/wells/WellSolverBase.cpp | 4 +- ...mpositionalMultiphaseReservoirAndWells.cpp | 1 - .../CoupledReservoirAndWellKernels.hpp | 86 ++-- 19 files changed, 621 insertions(+), 688 deletions(-) diff --git a/src/coreComponents/common/KernelLaunchSelectors.hpp b/src/coreComponents/common/KernelLaunchSelectors.hpp index 7b7ca2483e3..b8547458218 100644 --- a/src/coreComponents/common/KernelLaunchSelectors.hpp +++ b/src/coreComponents/common/KernelLaunchSelectors.hpp @@ -23,7 +23,8 @@ namespace geos { -namespace internal { +namespace internal +{ template< typename T, typename LAMBDA > void kernelLaunchSelectorThermalSwitch( T value, LAMBDA && lambda ) @@ -97,7 +98,7 @@ void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); - if ( n_phase == 1 ) + if( n_phase == 1 ) { switch( value ) { @@ -117,7 +118,7 @@ void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) { GEOS_ERROR( "Unsupported number of components: " << value ); } } } - else if ( n_phase == 2 ) + else if( n_phase == 2 ) { switch( value ) { @@ -138,7 +139,7 @@ void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) } } - else if ( n_phase == 3 ) + else if( n_phase == 3 ) { switch( value ) { diff --git a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp index 04487d6a0df..636becad333 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/CO2Brine/CO2BrineFluid.hpp @@ -364,7 +364,6 @@ CO2BrineFluid< PHASE1, PHASE2, FLASH >::KernelWrapper:: if( m_isThermal ) { - m_phase1.enthalpy.compute( pressure, temperatureInCelsius, phaseCompFraction.value[ip1].toSliceConst(), phaseCompFraction.derivs[ip1].toSliceConst(), diff --git a/src/coreComponents/mesh/ElementRegionManager.hpp b/src/coreComponents/mesh/ElementRegionManager.hpp index b94d6b08495..9a75cbc164b 100644 --- a/src/coreComponents/mesh/ElementRegionManager.hpp +++ b/src/coreComponents/mesh/ElementRegionManager.hpp @@ -557,8 +557,6 @@ class ElementRegionManager : public ObjectManagerBase template< typename SUBREGIONTYPE, typename ... SUBREGIONTYPES, typename LOOKUP_CONTAINER, typename LAMBDA > void forElementSubRegions( LOOKUP_CONTAINER const & targetRegions, LAMBDA && lambda ) { - for( auto jj : targetRegions ) - std::cout << "forElementSubRegions " << jj << std::endl; forElementSubRegionsComplete< SUBREGIONTYPE, SUBREGIONTYPES... >( targetRegions, [lambda = std::forward< LAMBDA >( lambda )]( localIndex const targetIndex, localIndex const, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index 6e09da364ff..076de25b77c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp @@ -1321,13 +1321,10 @@ void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( Dom MeshLevel const & mesh, arrayView1d< string const > const & regionNames ) { - std::cout << "assembleAccumulationAndVolumeBalanceTerms : domain " << domain.getName() << std::endl; mesh.getElemManager().forElementSubRegions( regionNames, [&]( localIndex const, ElementSubRegionBase const & subRegion ) { - std::cout << "assembleAccumulationAndVolumeBalanceTerms : subregion " << subRegion.getName() << std::endl; - string const dofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); string const & solidName = subRegion.getReference< string >( viewKeyStruct::solidNamesString() ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp index 819335acc8d..823a7d2b1c2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp @@ -481,6 +481,14 @@ real64 CompositionalMultiphaseFVM::scalingForSystemSolution( DomainPartition & d [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temperature = subRegion.getField< fields::flow::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); + + const integer temperatureOffset = m_numComponents+1; auto const subRegionData = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: @@ -489,16 +497,29 @@ real64 CompositionalMultiphaseFVM::scalingForSystemSolution( DomainPartition & d m_maxAbsolutePresChange, m_maxRelativeTempChange, m_maxCompFracChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, subRegion, - localSolution ) + localSolution, + temperatureOffset ) : isothermalCompositionalMultiphaseBaseKernels:: ScalingForSystemSolutionKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, @@ -571,8 +592,18 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temperature = + subRegion.getField< fields::flow::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); // check that pressure and component densities are non-negative // for thermal, check that temperature is above 273.15 K + const integer temperatureOffset = m_numComponents+1; auto const subRegionData = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: @@ -581,17 +612,30 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, m_allowNegativePressure, m_scalingType, scalingFactor, + pressure, + temperature, + compDens, + pressureScalingFactor, + temperatureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, subRegion, - localSolution ) + localSolution, + temperatureOffset ) : isothermalCompositionalMultiphaseBaseKernels:: SolutionCheckKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, m_allowNegativePressure, m_scalingType, scalingFactor, + pressure, + + compDens, + pressureScalingFactor, + + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp index 431a7320860..2f6ec3dd60c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp @@ -444,12 +444,24 @@ real64 CompositionalMultiphaseHybridFVM::scalingForSystemSolution( DomainPartiti mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temperature = subRegion.getField< fields::flow::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); auto const subRegionData = isothermalCompositionalMultiphaseBaseKernels:: ScalingForSystemSolutionKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, @@ -516,6 +528,15 @@ bool CompositionalMultiphaseHybridFVM::checkSystemSolution( DomainPartition & do mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, [&]( localIndex const, ElementSubRegionBase & subRegion ) { + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temperature = + subRegion.getField< fields::flow::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); // check that pressure and component densities are non-negative auto const subRegionData = isothermalCompositionalMultiphaseBaseKernels:: @@ -524,6 +545,10 @@ bool CompositionalMultiphaseHybridFVM::checkSystemSolution( DomainPartition & do m_allowNegativePressure, CompositionalMultiphaseFVM::ScalingType::Global, scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, elemDofKey, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp index a163ef23a32..b3f531f5e18 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp @@ -1472,20 +1472,19 @@ class ScalingForSystemSolutionKernelFactory createAndLaunch( real64 const maxRelativePresChange, real64 const maxAbsolutePresChange, real64 const maxCompFracChange, + arrayView1d< real64 const > const pressure, + arrayView1d< real64 const > const temperature, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + arrayView1d< real64 > temperatureScalingFactor, globalIndex const rankOffset, integer const numComp, string const dofKey, ElementSubRegionBase & subRegion, arrayView1d< real64 const > const localSolution ) { - arrayView1d< real64 const > const pressure = - subRegion.getField< fields::flow::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = - subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = - subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); + ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, rankOffset, numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); return ScalingForSystemSolutionKernel::launch< POLICY >( subRegion.size(), kernel ); @@ -1527,15 +1526,15 @@ class SolutionCheckKernel : public ScalingAndCheckingSystemSolutionKernelBase< i integer const allowNegativePressure, CompositionalMultiphaseFVM::ScalingType const scalingType, real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, globalIndex const rankOffset, integer const numComp, string const dofKey, ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution, - arrayView1d< real64 const > const pressure, - arrayView2d< real64 const, compflow::USD_COMP > const compDens, - arrayView1d< real64 > pressureScalingFactor, - arrayView1d< real64 > compDensScalingFactor ) + arrayView1d< real64 const > const localSolution ) : Base( rankOffset, numComp, dofKey, @@ -1772,22 +1771,20 @@ class SolutionCheckKernelFactory integer const allowNegativePressure, CompositionalMultiphaseFVM::ScalingType const scalingType, real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, globalIndex const rankOffset, integer const numComp, string const dofKey, ElementSubRegionBase & subRegion, arrayView1d< real64 const > const localSolution ) { - arrayView1d< real64 const > const pressure = - subRegion.getField< fields::flow::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = - subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = - subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); - SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, rankOffset, - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); + + SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, + pressure, compDens, pressureScalingFactor, compDensScalingFactor, rankOffset, + numComp, dofKey, subRegion, localSolution ); return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp index 9540147964e..4b667c9ac63 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp @@ -565,7 +565,8 @@ class ScalingForSystemSolutionKernel : public isothermalCompositionalMultiphaseB arrayView2d< real64 const, compflow::USD_COMP > const compDens, arrayView1d< real64 > pressureScalingFactor, arrayView1d< real64 > compDensScalingFactor, - arrayView1d< real64 > temperatureScalingFactor ) + arrayView1d< real64 > temperatureScalingFactor, + integer const temperatureOffset ) : Base( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, @@ -580,7 +581,8 @@ class ScalingForSystemSolutionKernel : public isothermalCompositionalMultiphaseB compDensScalingFactor ), m_maxRelativeTempChange( maxRelativeTempChange ), m_temperature( temperature ), - m_temperatureScalingFactor( temperatureScalingFactor ) + m_temperatureScalingFactor( temperatureScalingFactor ), + m_temperatureOffset( temperatureOffset ) {} /** @@ -609,7 +611,7 @@ class ScalingForSystemSolutionKernel : public isothermalCompositionalMultiphaseB { // compute the change in temperature real64 const temp = m_temperature[ei]; - real64 const absTempChange = LvArray::math::abs( m_localSolution[stack.localRow + m_numComp + 1] ); + real64 const absTempChange = LvArray::math::abs( m_localSolution[stack.localRow + m_temperatureOffset] ); if( stack.localMaxDeltaTemp < absTempChange ) { stack.localMaxDeltaTemp = absTempChange; @@ -648,11 +650,15 @@ class ScalingForSystemSolutionKernel : public isothermalCompositionalMultiphaseB /// View on the scaling factor arrayView1d< real64 > const m_temperatureScalingFactor; + /// Temperature offset in solution array + integer const m_temperatureOffset; + }; /** * @class ScalingForSystemSolutionKernelFactory */ + class ScalingForSystemSolutionKernelFactory { public: @@ -675,22 +681,26 @@ class ScalingForSystemSolutionKernelFactory real64 const maxAbsolutePresChange, real64 const maxRelativeTempChange, real64 const maxCompFracChange, + arrayView1d< real64 const > const pressure, + arrayView1d< real64 const > const temperature, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + arrayView1d< real64 > temperatureScalingFactor, + + globalIndex const rankOffset, integer const numComp, string const dofKey, ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) + arrayView1d< real64 const > const localSolution, + integer const temperatureOffset ) { - arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temperature = subRegion.getField< fields::flow::temperature >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); + ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxRelativeTempChange, maxCompFracChange, rankOffset, numComp, dofKey, subRegion, localSolution, pressure, temperature, compDens, pressureScalingFactor, - temperatureScalingFactor, compDensScalingFactor ); + compDensScalingFactor, temperatureScalingFactor, temperatureOffset ); return thermalCompositionalMultiphaseBaseKernels:: ScalingForSystemSolutionKernel::launch< POLICY >( subRegion.size(), kernel ); } @@ -731,32 +741,36 @@ class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels: integer const allowNegativePressure, CompositionalMultiphaseFVM::ScalingType const scalingType, real64 const scalingFactor, - globalIndex const rankOffset, - integer const numComp, - string const dofKey, - ElementSubRegionBase const & subRegion, - arrayView1d< real64 const > const localSolution, arrayView1d< real64 const > const pressure, arrayView1d< real64 const > const temperature, arrayView2d< real64 const, compflow::USD_COMP > const compDens, arrayView1d< real64 > pressureScalingFactor, arrayView1d< real64 > compDensScalingFactor, - arrayView1d< real64 > temperatureScalingFactor ) + arrayView1d< real64 > temperatureScalingFactor, + globalIndex const rankOffset, + integer const numComp, + string const dofKey, + ElementSubRegionBase const & subRegion, + arrayView1d< real64 const > const localSolution, + + integer const temperatureOffset ) : Base( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, + + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, rankOffset, numComp, dofKey, subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), + localSolution ), m_temperature( temperature ), - m_temperatureScalingFactor( temperatureScalingFactor ) + m_temperatureScalingFactor( temperatureScalingFactor ), + m_temperatureOffset( temperatureOffset ) {} /** @@ -772,7 +786,7 @@ class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels: { bool const localScaling = m_scalingType == CompositionalMultiphaseFVM::ScalingType::Local; // compute the change in temperature - real64 const newTemp = m_temperature[ei] + (localScaling ? m_temperatureScalingFactor[ei] : m_scalingFactor * m_localSolution[stack.localRow + m_numComp + 1]); + real64 const newTemp = m_temperature[ei] + (localScaling ? m_temperatureScalingFactor[ei] : m_scalingFactor * m_localSolution[stack.localRow + m_temperatureOffset]); if( newTemp < minTemperature ) { stack.localMinVal = 0; @@ -788,6 +802,9 @@ class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels: /// View on the scaling factor arrayView1d< real64 const > const m_temperatureScalingFactor; + /// Offset to temperature variable + integer m_temperatureOffset; + }; /** @@ -815,24 +832,27 @@ class SolutionCheckKernelFactory integer const allowNegativePressure, CompositionalMultiphaseFVM::ScalingType const scalingType, real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView1d< real64 const > const temperature, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > temperatureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, + + + globalIndex const rankOffset, integer const numComp, string const dofKey, ElementSubRegionBase & subRegion, - arrayView1d< real64 const > const localSolution ) + arrayView1d< real64 const > const localSolution, + integer temperatureOffset ) { - arrayView1d< real64 const > const pressure = - subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temperature = - subRegion.getField< fields::flow::temperature >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = - subRegion.getField< fields::flow::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); + SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, + pressure, temperature, compDens, pressureScalingFactor, compDensScalingFactor, temperatureScalingFactor, rankOffset, numComp, dofKey, subRegion, localSolution, - pressure, temperature, compDens, pressureScalingFactor, temperatureScalingFactor, compDensScalingFactor ); + temperatureOffset ); return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index aff0b356153..3a66d02011f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -101,6 +101,12 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, setApplyDefaultValue( -1.0 ). // disabled by default setDescription( "Maximum (absolute) pressure change in a Newton iteration" ); + this->registerWrapper( viewKeyStruct::maxRelativeTempChangeString(), &m_maxRelativeTempChange ). + setSizedFromParent( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setApplyDefaultValue( 1.0 ). + setDescription( "Maximum (relative) change in temperature between two Newton iterations " ); + this->registerWrapper( viewKeyStruct::allowLocalCompDensChoppingString(), &m_allowCompDensChopping ). setSizedFromParent( 0 ). setInputFlag( InputFlags::OPTIONAL ). @@ -224,8 +230,8 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) PerforationData & perforationData = *subRegion.getPerforationData(); perforationData.registerField< fields::well::compPerforationRate >( getName() ). reference().resizeDimension< 1 >( m_numComponents ); - perforationData.registerField< fields::well::dCompPerforationRate >( getName() ). - reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); + + perforationData.registerField< fields::well::dCompPerforationRate >( getName() ).reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents+ 2 ); if( fluid.isThermal() ) { perforationData.registerField< fields::well::energyPerforationFlux >( getName() ); @@ -806,7 +812,6 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg GEOS_UNUSED_VAR( massUnit ); using Deriv = multifluid::DerivativeOffset; stackArray1d< real64, maxNumComp > work( numComp ); - // Step 1: evaluate the phase and total density in the reference element // We need to evaluate the density as follows: @@ -942,13 +947,11 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { using FluidType = TYPEOFREF( castedFluid ); using ExecPolicy = typename FluidType::exec_policy; typename FluidType::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - thermalCompositionalMultiphaseBaseKernels:: FluidUpdateKernel:: launch< ExecPolicy >( subRegion.size(), @@ -1143,8 +1146,11 @@ void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & s updateVolRatesForConstraint( subRegion ); // tjb - thermal +++ looks like it does a lot more... // update densities, phase fractions, phase volume fractions + updateFluidModel( subRegion ); // Calculate fluid properties + updatePhaseVolumeFraction( subRegion ); // tjb - thermal + updateTotalMassDensity( subRegion ); // tjb - thermal // update the current BHP pressure @@ -1501,8 +1507,6 @@ integer numNorm = 1; // mass balance else { resNorm= MpiWrapper::max( resNorm ); - - if( getLogLevel() >= 1 && logger::internal::rank == 0 ) { std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} )", coupledSolverAttributePrefix(), resNorm ); @@ -1518,7 +1522,7 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, arrayView1d< real64 const > const & localRhs ) { - return calculateResidualNorm1( time_n, dt, domain, dofManager, localRhs); + return calculateResidualNorm1( time_n, dt, domain, dofManager, localRhs ); GEOS_MARK_FUNCTION; @@ -1593,6 +1597,8 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, string const wellDofKey = dofManager.getKey( wellElementDofName() ); real64 scalingFactor = 1.0; + if( 0 ) + { forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) @@ -1620,6 +1626,107 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, } ); return LvArray::math::max( MpiWrapper::min( scalingFactor ), m_minScalingFactor ); + } + else + { + real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0; + real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 const > const temperature = subRegion.getField< fields::well::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + const integer temperatureOffset = m_numComponents+2; + auto const subRegionData = + m_isThermal + ? thermalCompositionalMultiphaseBaseKernels:: + ScalingForSystemSolutionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, + m_maxAbsolutePresChange, + m_maxRelativeTempChange, + m_maxCompFracChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution, + temperatureOffset ) + : isothermalCompositionalMultiphaseBaseKernels:: + ScalingForSystemSolutionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, + m_maxAbsolutePresChange, + m_maxCompFracChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution ); + + + scalingFactor = scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); + + maxDeltaPres = std::max( maxDeltaPres, subRegionData.localMaxDeltaPres ); + maxDeltaCompDens = std::max( maxDeltaCompDens, subRegionData.localMaxDeltaCompDens ); + maxDeltaTemp = std::max( maxDeltaTemp, subRegionData.localMaxDeltaTemp ); + minPresScalingFactor = std::min( minPresScalingFactor, subRegionData.localMinPresScalingFactor ); + minCompDensScalingFactor = std::min( minCompDensScalingFactor, subRegionData.localMinCompDensScalingFactor ); + minTempScalingFactor = std::min( minTempScalingFactor, subRegionData.localMinTempScalingFactor ); + } ); + } ); + + scalingFactor = MpiWrapper::min( scalingFactor ); + maxDeltaPres = MpiWrapper::max( maxDeltaPres ); + maxDeltaCompDens = MpiWrapper::max( maxDeltaCompDens ); + minPresScalingFactor = MpiWrapper::min( minPresScalingFactor ); + minCompDensScalingFactor = MpiWrapper::min( minCompDensScalingFactor ); + + string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well pressure change: {} Pa (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaPres, 3 ) ) ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well component density change: {} {} (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaCompDens, 3 ), massUnit ) ); + + if( m_isThermal ) + { + maxDeltaTemp = MpiWrapper::max( maxDeltaTemp ); + minTempScalingFactor = MpiWrapper::min( minTempScalingFactor ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well temperature change: {} K (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaTemp, 3 ) ) ); + } + + + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well pressure scaling factor: {}", getName(), minPresScalingFactor ) ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well component density scaling factor: {}", getName(), minCompDensScalingFactor ) ); + if( m_isThermal ) + { + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well temperature scaling factor: {}", getName(), minTempScalingFactor ) ); + } + + + return LvArray::math::max( scalingFactor, m_minScalingFactor ); + } } bool @@ -1632,6 +1739,9 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, string const wellDofKey = dofManager.getKey( wellElementDofName() ); integer localCheck = 1; + if( 0 ) + { + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) @@ -1640,12 +1750,26 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, [&]( localIndex const, WellElementSubRegion & subRegion ) { + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 const > const temperature = + subRegion.getField< fields::well::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + auto const subRegionData = compositionalMultiphaseWellKernels:: SolutionCheckKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, CompositionalMultiphaseFVM::ScalingType::Global, scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, dofManager.rankOffset(), m_numComponents, wellDofKey, @@ -1661,6 +1785,103 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, localCheck = std::min( localCheck, subRegionData.localMinVal ); } ); } ); + } + else + { + + real64 minPres = 0.0, minDens = 0.0, minTotalDens = 0.0; + integer numNegPres = 0, numNegDens = 0, numNegTotalDens = 0; + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + //integer const m_allowCompDensChopping(true); + integer const m_allowNegativePressure( false ); + CompositionalMultiphaseFVM::ScalingType const m_scalingType( CompositionalMultiphaseFVM::ScalingType::Global ); + arrayView1d< real64 const > const pressure = + subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 const > const temperature = + subRegion.getField< fields::well::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = + subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + + // check that pressure and component densities are non-negative + // for thermal, check that temperature is above 273.15 K + const integer temperatureOffset = m_numComponents+2; + auto const subRegionData = + m_isThermal + ? thermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + temperature, + compDens, + pressureScalingFactor, + temperatureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution, + temperatureOffset ) + : isothermalCompositionalMultiphaseBaseKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + m_allowNegativePressure, + m_scalingType, + scalingFactor, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution ); + + localCheck = std::min( localCheck, subRegionData.localMinVal ); + + minPres = std::min( minPres, subRegionData.localMinPres ); + minDens = std::min( minDens, subRegionData.localMinDens ); + minTotalDens = std::min( minTotalDens, subRegionData.localMinTotalDens ); + numNegPres += subRegionData.localNumNegPressures; + numNegDens += subRegionData.localNumNegDens; + numNegTotalDens += subRegionData.localNumNegTotalDens; + } ); + } ); + + minPres = MpiWrapper::min( minPres ); + minDens = MpiWrapper::min( minDens ); + minTotalDens = MpiWrapper::min( minTotalDens ); + numNegPres = MpiWrapper::sum( numNegPres ); + numNegDens = MpiWrapper::sum( numNegDens ); + numNegTotalDens = MpiWrapper::sum( numNegTotalDens ); + + if( numNegPres > 0 ) + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative well pressure values: {}, minimum value: {} Pa", + getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); + string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; + if( numNegDens > 0 ) + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative well component density values: {}, minimum value: {} {}}", + getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + if( minTotalDens > 0 ) + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative total well density values: {}, minimum value: {} {}}", + getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); + + } return MpiWrapper::min( localCheck ); } @@ -1879,12 +2100,12 @@ if( isThermal() ) { // synchronize FieldIdentifiers fieldsToBeSync; -if ( isThermal() ) + if( isThermal() ) { fieldsToBeSync.addElementFields( { fields::well::pressure::key(), -fields::well::temperature::key(), fields::well::globalCompDensity::key(), - fields::well::mixtureConnectionRate::key() }, + fields::well::mixtureConnectionRate::key(), + fields::well::temperature::key() }, regionNames ); } else @@ -1962,7 +2183,7 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & subRegion.getField< fields::well::pressure_n >(); wellElemPressure.setValues< parallelDevicePolicy<> >( wellElemPressure_n ); -if ( isThermal() ) + if( isThermal() ) { // get a reference to the primary variables on well elements arrayView1d< real64 > const & wellElemTemperature = @@ -2204,23 +2425,27 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, [&]( localIndex const, WellElementSubRegion & subRegion ) { + // get a reference to the primary variables on well elements arrayView1d< real64 const > const & wellElemPressure = subRegion.getField< fields::well::pressure >(); + arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity = + subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 const > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + arrayView1d< real64 > const & wellElemPressure_n = subRegion.getField< fields::well::pressure_n >(); wellElemPressure_n.setValues< parallelDevicePolicy<> >( wellElemPressure ); -if ( isThermal() ) + if( isThermal() ) { - arrayView1d< real64 const > const & wellElemTemperature = - subRegion.getField< fields::well::temperature >(); + arrayView1d< real64 > const & wellElemTemperature_n = subRegion.getField< fields::well::temperature_n >(); wellElemTemperature_n.setValues< parallelDevicePolicy<> >( wellElemTemperature ); } - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity = - subRegion.getField< fields::well::globalCompDensity >(); + arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity_n = subRegion.getField< fields::well::globalCompDensity_n >(); wellElemGlobalCompDensity_n.setValues< parallelDevicePolicy<> >( wellElemGlobalCompDensity ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 54061cb2b55..1a711f7d520 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -303,6 +303,8 @@ virtual void assembleSystem( real64 const time, static constexpr char const * maxAbsolutePresChangeString() { return "maxAbsolutePressureChange"; } + static constexpr char const * maxRelativeTempChangeString() { return "maxRelativeTemperatureChange"; } + static constexpr char const * allowLocalCompDensChoppingString() { return CompositionalMultiphaseBase::viewKeyStruct::allowLocalCompDensChoppingString(); } // control data (not registered on the mesh) @@ -411,6 +413,9 @@ virtual void assembleSystem( real64 const time, /// maximum (absolute) change in pressure between two Newton iterations real64 m_maxAbsolutePresChange; + /// maximum (relative) change in temperature in a Newton iteration + real64 m_maxRelativeTempChange; + /// minimum value of the scaling factor obtained by enforcing maxCompFracChange real64 m_minScalingFactor; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index 9e44861239f..e2b6b47a3c1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -169,6 +169,12 @@ ControlEquationHelper:: { compDofColIndices[ ic ] = presDofColIndex + ic + 1; } + // remove above + globalIndex dofColIndices[COFFSET_WJ::nDer]{}; + for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic ) + { + dofColIndices[ ic ] = dofNumber + ic; + } real64 controlEqn = 0; real64 dControlEqn_dPres = 0; @@ -252,6 +258,8 @@ ControlEquationHelper:: GEOS_ERROR( "This constraint is not supported in CompositionalMultiphaseWell" ); } localRhs[eqnRowIndex] += controlEqn; + if( 0 ) + { localMatrix.addToRow< serialAtomic >( eqnRowIndex, &presDofColIndex, &dControlEqn_dPres, @@ -264,6 +272,14 @@ ControlEquationHelper:: compDofColIndices, dControlEqn_dComp, NC ); + } + else + { + localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex, + dofColIndices, + dControlEqn, + COFFSET_WJ::nDer ); + } // tjb- remove when safe and modify local matrix updates assert( fabs( dControlEqn[COFFSET_WJ::dP] -dControlEqn_dPres ) < FLT_EPSILON ); assert( fabs( dControlEqn[COFFSET_WJ::dQ] - dControlEqn_dRate ) < FLT_EPSILON ); @@ -384,7 +400,6 @@ FluxKernel:: localIndex const iwelemNext = nextWellElemIndex[iwelem]; real64 const currentConnRate = connRate[iwelem]; -std::cout << " connRate " << iwelem << " " << currentConnRate << std::endl; localIndex iwelemUp = -1; if( iwelemNext < 0 && !isProducer ) // exit connection, injector @@ -653,17 +668,17 @@ GEOS_UNUSED_VAR( dTotalMassDens_dPres ); // localPresRelJacbain contains dP, dC and potentially dT derivatives for neighboring well elements // TAG::NEXT is 1, CURRENT is 0 , not sure why indexes are setup as below localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)] = ( 1 - dAvgMassDens_dPresNext * gravD ); - localPresRelJacobian[TAG::CURRENT *(NC+1)] = ( -1 - dAvgMassDens_dPresCurrent * gravD ); + localPresRelJacobian[TAG::CURRENT *(NC+1+IS_THERMAL)] = ( -1 - dAvgMassDens_dPresCurrent * gravD ); for( integer ic = 0; ic < NC; ++ic ) { localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; - localPresRelJacobian[TAG::CURRENT *(NC+1) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; + localPresRelJacobian[TAG::CURRENT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; } if constexpr ( IS_THERMAL ) { localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDensNext[Deriv::dT]; - localPresRelJacobian[TAG::CURRENT *(NC+1)+1] = 0.5 * dTotalMassDens[Deriv::dT]; + localPresRelJacobian[TAG::CURRENT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDens[Deriv::dT]; } } @@ -1377,10 +1392,6 @@ PerforationKernel:: // tjb- remove when safe for( integer ic = 0; ic < NC; ic++ ) { - if( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic] ) > FLT_EPSILON ) - { - std::cout << ic << " " << dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] << " " << dCompPerfRate_dPres[TAG::RES][ic] << std::endl; - } assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic] ) < FLT_EPSILON ); assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic] ) < FLT_EPSILON ); for( integer jc = 0; jc < NC; ++jc ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 559363546a8..9c037212727 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -866,9 +866,7 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); // Step 4: compute the contribution to the residual -std::cout << "bNormalize " << idof << " " << stack.localRow + idof << " " << m_localResidual[stack.localRow + idof] << " " << normalizer << std::endl; real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; -std::cout << "Normalizer " << val << " " << stack.localValue[0] << std::endl; if( val > stack.localValue[0] ) { stack.localValue[0] = val; @@ -1047,19 +1045,21 @@ class SolutionCheckKernelFactory createAndLaunch( integer const allowCompDensChopping, CompositionalMultiphaseFVM::ScalingType const scalingType, real64 const scalingFactor, + arrayView1d< real64 const > const pressure, + arrayView2d< real64 const, compflow::USD_COMP > const compDens, + arrayView1d< real64 > pressureScalingFactor, + arrayView1d< real64 > compDensScalingFactor, globalIndex const rankOffset, integer const numComp, string const dofKey, ElementSubRegionBase & subRegion, arrayView1d< real64 const > const localSolution ) { - arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + isothermalCompositionalMultiphaseBaseKernels:: - SolutionCheckKernel kernel( allowCompDensChopping, 0, scalingType, scalingFactor, rankOffset, // no negative pressure - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); + SolutionCheckKernel kernel( allowCompDensChopping, 0, scalingType, scalingFactor, + pressure, compDens, pressureScalingFactor, compDensScalingFactor, rankOffset, + numComp, dofKey, subRegion, localSolution ); return isothermalCompositionalMultiphaseBaseKernels:: SolutionCheckKernel:: launch< POLICY >( subRegion.size(), kernel ); @@ -1214,7 +1214,7 @@ class ElementBasedAssemblyKernel { stack.dofColIndices[numComp+1] = m_dofNumber[ei] + WJ_COFFSET::dT; } - if( 0 ) + if( 1 ) for( integer jc = 0; jc < numEqn; ++jc ) { stack.localResidual[jc] = 0.0; @@ -1267,9 +1267,7 @@ real64 dPhaseAmount[FLUID_PROP_COFFSET::nDer]{}; for( integer ip = 0; ip < m_numPhases; ++ip ) { real64 const phaseAmount = stack.volume * phaseVolFrac[ip] * phaseDens[ip]; -std::cout << " phaseAmount " << ip << " " << phaseVolFrac[ip] << " " << phaseDens[ip] << std::endl; real64 const phaseAmount_n = stack.volume * phaseVolFrac_n[ip] * phaseDens_n[ip]; -std::cout << " phaseAmount_n " << ip << " " << phaseVolFrac[ip] << " " << phaseDens[ip] << std::endl; //remove tjb real64 const dPhaseAmount_dP = stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); @@ -1387,7 +1385,6 @@ if constexpr ( IS_THERMAL ) } // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) stack.localResidual[numComp] = stack.volume * oneMinusPhaseVolFracSum; - std::cout << "vol bal res " << stack.localResidual[numComp] << std::endl; for( integer idof = 0; idof < numComp+1+IS_THERMAL; ++idof ) { stack.localJacobian[numComp][idof] *= stack.volume; @@ -1422,7 +1419,6 @@ if constexpr ( IS_THERMAL ) integer const numRows = numComp+1+ IS_THERMAL; for( integer i = 0; i < numRows; ++i ) { -std::cout << "accum+vb resd " << m_localRhs[stack.eqnRowIndices[i]] << " " << stack.eqnRowIndices[i] << " " << stack.localResidual[i] << std::endl; m_localRhs[stack.eqnRowIndices[i]] += stack.localResidual[i]; m_localMatrix.addToRow< serialAtomic >( stack.eqnRowIndices[i], stack.dofColIndices, @@ -1568,416 +1564,7 @@ integer constexpr istherm = IS_THERMAL(); * @tparam NUM_DOF number of degrees of freedom * @brief Define the interface for the assembly kernel in charge of flux terms */ -template< integer NC, integer NUM_DOF > -class FaceBasedAssemblyKernel_ORG -{ -public: - - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using TAG = compositionalMultiphaseWellKernels::ElemTag; - - - /// Compile time value for the number of components - static constexpr integer numComp = NC; - - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; - - - /** - * @brief Constructor for the kernel interface -* @param[in] dt time step size - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor - * @param[in] compFlowAccessors - * @param[in] multiFluidAccessors - * @param[in] capPressureAccessors - * @param[in] permeabilityAccessors - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - * @param[in] kernelFlags flags packed together - */ - FaceBasedAssemblyKernel_ORG( real64 const dt, - globalIndex const rankOffset, - string const wellDofKey, - WellControls const & wellControls, - ElementSubRegionBase const & subRegion, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) - : - m_dt( dt ), - m_rankOffset( rankOffset ), - m_wellElemDofNumber ( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), - m_nextWellElemIndex ( subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString()) ), - m_connRate ( subRegion.getField< fields::well::mixtureConnectionRate >() ), - m_wellElemCompFrac ( subRegion.getField< fields::well::globalCompFraction >() ), - m_dWellElemCompFrac_dCompDens ( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ), - m_localMatrix( localMatrix ), - m_localRhs ( localRhs ), - m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ), - m_isProducer ( wellControls.isProducer() ), - m_injection ( wellControls.getInjectionStream() ) - { } - - - GEOS_HOST_DEVICE - inline - void - computeExit( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & oneSidedFlux )[NC], - real64 ( & oneSidedFluxJacobian_dRate )[NC][1], - real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ) const - { - for( integer ic = 0; ic < NC; ++ic ) - { - oneSidedFlux[ic] = -dt * compFlux[ic]; - - // derivative with respect to rate - oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; - - // derivative with respect to upstream pressure - oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; - - // derivatives with respect to upstream component densities - for( integer jdof = 0; jdof < NC; ++jdof ) - { - oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; - } - } - } - - GEOS_HOST_DEVICE - inline - void - compute( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & localFlux )[2*NC], - real64 ( & localFluxJacobian_dRate )[2*NC][1], - real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ) const - { - // flux terms - for( integer ic = 0; ic < NC; ++ic ) - { - localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; - localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; - - // derivative with respect to rate - localFluxJacobian_dRate[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dRate[ic]; - localFluxJacobian_dRate[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dRate[ic]; - - // derivative with respect to upstream pressure - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dPresUp[ic]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dPresUp[ic]; - - // derivatives with respect to upstream component densities - for( integer jdof = 0; jdof < NC; ++jdof ) - { - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; - } - } - } - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes - * @param[in] ie the element index - * @param[inout] stack the stack variables - * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void computeFlux( localIndex const iwelem, - FUNC && compFluxKernelOp = NoOpFunc{} ) const - { -GEOS_UNUSED_VAR( compFluxKernelOp ); - using namespace compositionalMultiphaseUtilities; - - // create local work arrays - real64 compFracUp[NC]{}; - real64 dCompFrac_dCompDensUp[NC][NC]{}; - - real64 compFlux[NC]{}; - real64 dCompFlux_dRate[NC]{}; - real64 dCompFlux_dPresUp[NC]{}; - real64 dCompFlux_dCompDensUp[NC][NC]{}; - - // Step 1) decide the upwind well element - - /* currentConnRate < 0 flow from iwelem to iwelemNext - * currentConnRate > 0 flow from iwelemNext to iwelem - * With this convention, currentConnRate < 0 at the last connection for a producer - * currentConnRate > 0 at the last connection for a injector - */ - - localIndex const iwelemNext = m_nextWellElemIndex[iwelem]; - real64 const currentConnRate = m_connRate[iwelem]; - localIndex iwelemUp = -1; - if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector - { - // we still need to define iwelemUp for Jacobian assembly - iwelemUp = iwelem; - - // just copy the injection stream into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = m_injection[ic]; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFrac_dCompDensUp[ic][jc] = 0.0; - } - } - } - else - { - // first set iwelemUp to the upstream cell - if( ( iwelemNext < 0 && m_isProducer ) // exit connection, producer - || currentConnRate < 0 ) // not an exit connection, iwelem is upstream - { - iwelemUp = iwelem; - } - else // not an exit connection, iwelemNext is upstream - { - iwelemUp = iwelemNext; - } - - // copy the vars of iwelemUp into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = m_wellElemCompFrac[iwelemUp][ic]; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFrac_dCompDensUp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; - } - } - } - - // Step 2) compute upstream transport coefficient - - for( integer ic = 0; ic < NC; ++ic ) - { - compFlux[ic] = compFracUp[ic] * currentConnRate; - dCompFlux_dRate[ic] = compFracUp[ic]; - dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; - } - } - - globalIndex const offsetUp = m_wellElemDofNumber[iwelemUp]; - globalIndex const offsetCurrent = m_wellElemDofNumber[iwelem]; - - if( iwelemNext < 0 ) // exit connection - { - // for this case, we only need NC mass conservation equations - // so we do not use the arrays initialized before the loop - real64 oneSidedFlux[NC]{}; - real64 oneSidedFluxJacobian_dRate[NC][1]{}; - real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; - - computeExit ( m_dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - oneSidedFlux, - oneSidedFluxJacobian_dRate, - oneSidedFluxJacobian_dPresCompUp ); - - - globalIndex oneSidedEqnRowIndices[NC]{}; - globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; - globalIndex oneSidedDofColIndices_dRate = 0; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - oneSidedEqnRowIndices[ic] = offsetUp + ROFFSET::MASSBAL + ic - m_rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - oneSidedDofColIndices_dRate = offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - oneSidedDofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - - if( m_useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); - } - - for( integer i = 0; i < NC; ++i ) - { - if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) - { - m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - &oneSidedDofColIndices_dRate, - oneSidedFluxJacobian_dRate[i], - 1 ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - oneSidedDofColIndices_dPresCompUp, - oneSidedFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); - } - } - } - else // not an exit connection - { - real64 localFlux[2*NC]{}; - real64 localFluxJacobian_dRate[2*NC][1]{}; - real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; - - compute( m_dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - localFlux, - localFluxJacobian_dRate, - localFluxJacobian_dPresCompUp ); - - - globalIndex eqnRowIndices[2*NC]{}; - globalIndex dofColIndices_dPresCompUp[NC+1]{}; - globalIndex dofColIndices_dRate = 0; - - globalIndex const offsetNext = m_wellElemDofNumber[iwelemNext]; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - eqnRowIndices[TAG::NEXT *NC+ic] = offsetNext + ROFFSET::MASSBAL + ic - m_rankOffset; - eqnRowIndices[TAG::CURRENT *NC+ic] = offsetCurrent + ROFFSET::MASSBAL + ic - m_rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - dofColIndices_dRate = offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - dofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - - if( m_useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); - } - - for( integer i = 0; i < 2*NC; ++i ) - { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) - { -std::cout << i << " " << eqnRowIndices[i] << " " << dofColIndices_dRate << std::endl; - std::cout.flush(); - m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], - &dofColIndices_dRate, - localFluxJacobian_dRate[i], - 1 ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices_dPresCompUp, - localFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localFlux[i] ); - } - } - } -//compFluxKernelOp(iwelemNext,iwelemUp,currentConnRate, offsetUp, offsetCurrent); - } - - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElements the number of elements - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numElements, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) - { - //typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - // kernelComponent.numPointsInFlux( iconn ) ); - - //kernelComponent.setup( iconn, stack ); - kernelComponent.computeFlux( ie ); - //kernelComponent.complete( iconn, stack ); - } ); - } - -protected: - /// Time step size - real64 const m_dt; - /// Rank offset for calculating row/col Jacobian indices - integer const m_rankOffset; - - /// Reference to the degree-of-freedom numbers - arrayView1d< globalIndex const > const m_wellElemDofNumber; - /// Next element index, needed since iterating over element nodes, not edges - arrayView1d< localIndex const > const m_nextWellElemIndex; - - /// Connection rate - arrayView1d< real64 const > const m_connRate; - - - /// Element component fraction - arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; - /// Element component fraction derivatives - arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - - /// Kernel option flag - integer const m_useTotalMassEquation; - - /// Well type - bool const m_isProducer; - - /// Injection stream composition - arrayView1d< real64 const > const m_injection; - - -}; template< integer NC, integer IS_THERMAL > class FaceBasedAssemblyKernel @@ -2039,7 +1626,7 @@ class FaceBasedAssemblyKernel m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ), m_isProducer ( wellControls.isProducer() ), m_injection ( wellControls.getInjectionStream() ) - { } + {} struct StackVariables { @@ -2143,15 +1730,7 @@ class FaceBasedAssemblyKernel real64 work[CP_Deriv::nDer]{}; shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, 1, stack.localFluxJacobian_dQ, work ); shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numEqn, CP_Deriv::nDer, stack.localFluxJacobian, work ); - for( integer ic=0; ic 0.0; - if ( ! phaseExists ) + if( !phaseExists ) continue; double pflux = stack.m_wellElemPhaseVolFrac[iwelem][ip]*flux; real64 const wellelem_enthalpy = stack.m_wellElemPhaseEnthalpy[iwelem][0][ip]; stack.m_energyPerfFlux[iperf] += pflux * wellelem_enthalpy; + // energy equation derivatives WRT res P & T - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy ; - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy ; + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy; + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy; + // energy equation derivatives WRT well P & T stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy - + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dP] - + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][CP_Deriv::dP]; - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy - + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][CP_Deriv::dT] - + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][CP_Deriv::dT]; - // energy equation derivatives WRT reservoir dens + + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dP] + + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dP]; + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][Deriv::dT] * wellelem_enthalpy + + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dT] + + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dT]; + + //energy equation + for( integer ic=0; ic 0.0; // tjb- remove when safe for( integer ic = 0; ic < NC; ic++ ) { - if( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) > FLT_EPSILON ) - { - std::cout << ic << " " << m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] << " " << m_dCompPerfRate_dPres[iperf][TAG::RES][ic] << std::endl; - } - assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) < FLT_EPSILON ); - assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] ) < FLT_EPSILON ); for( integer jc = 0; jc < NC; ++jc ) { - assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] ) < FLT_EPSILON ); - assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] ) < FLT_EPSILON ); + assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] ) < FLT_EPSILON ); } } //compFluxKernelOp(er, esr, ei, potDiff, potGrad, flux, dFlux); @@ -739,7 +745,7 @@ bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) { - kernelComponent.computeFlux(iperf, kernelComponent.m_stackVariables); + kernelComponent.computeFlux( iperf, kernelComponent.m_stackVariables ); } ); } @@ -748,37 +754,37 @@ bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; StackVariables m_stackVariables; protected: - ElementViewConst< arrayView1d< real64 const > > const m_resPres; - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_resPhaseVolFrac; - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dResPhaseVolFrac; - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dResCompFrac_dCompDens; - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseDens; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseDens; - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseVisc; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseVisc; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const m_resPhaseCompFrac; - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const m_dResPhaseCompFrac; - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const m_resPhaseRelPerm; - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const m_dResPhaseRelPerm_dPhaseVolFrac; - arrayView1d< real64 const > const m_wellElemGravCoef; - arrayView1d< real64 const > const m_wellElemPres; - arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompDens; - arrayView1d< real64 const > const m_wellElemTotalMassDens; - arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens; - arrayView1d< real64 const > const m_dWellElemTotalMassDens_dPres; - arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens_dCompDens; - arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; - arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; - arrayView1d< real64 const > const m_perfGravCoef; - arrayView1d< localIndex const > const m_perfWellElemIndex; - arrayView1d< real64 const > const m_perfTrans; - arrayView1d< localIndex const > const m_resElementRegion; - arrayView1d< localIndex const > const m_resElementSubRegion; - arrayView1d< localIndex const > const m_resElementIndex; - arrayView2d< real64 > const m_compPerfRate; - arrayView4d< real64 > const m_dCompPerfRate; - arrayView3d< real64 > const m_dCompPerfRate_dPres; - arrayView4d< real64 > const m_dCompPerfRate_dComp; + ElementViewConst< arrayView1d< real64 const > > const m_resPres; + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_resPhaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dResPhaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dResCompFrac_dCompDens; + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseDens; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseDens; + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseVisc; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseVisc; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const m_resPhaseCompFrac; + ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const m_dResPhaseCompFrac; + ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const m_resPhaseRelPerm; + ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const m_dResPhaseRelPerm_dPhaseVolFrac; + arrayView1d< real64 const > const m_wellElemGravCoef; + arrayView1d< real64 const > const m_wellElemPres; + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompDens; + arrayView1d< real64 const > const m_wellElemTotalMassDens; + arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens; + arrayView1d< real64 const > const m_dWellElemTotalMassDens_dPres; + arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens_dCompDens; + arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; + arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; + arrayView1d< real64 const > const m_perfGravCoef; + arrayView1d< localIndex const > const m_perfWellElemIndex; + arrayView1d< real64 const > const m_perfTrans; + arrayView1d< localIndex const > const m_resElementRegion; + arrayView1d< localIndex const > const m_resElementSubRegion; + arrayView1d< localIndex const > const m_resElementIndex; + arrayView2d< real64 > const m_compPerfRate; + arrayView4d< real64 > const m_dCompPerfRate; + arrayView3d< real64 > const m_dCompPerfRate_dPres; + arrayView4d< real64 > const m_dCompPerfRate_dComp; bool const m_disableReservoirToWellFlow; @@ -815,7 +821,7 @@ class PerforationFluxKernelFactory ElementRegionManager & elemManager, integer const disableReservoirToWellFlow ) { - geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases , [&]( auto NC, auto NP ) + geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases, [&]( auto NC, auto NP ) { integer constexpr NUM_COMP = NC(); integer constexpr NUM_PHASE = NP(); @@ -825,7 +831,7 @@ class PerforationFluxKernelFactory typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); //typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, flowSolverName ); - typename kernelType::RelPermAccessors relPermAccessors( elemManager ,flowSolverName ); + typename kernelType::RelPermAccessors relPermAccessors( elemManager, flowSolverName ); //ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = // elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); //dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); @@ -846,11 +852,11 @@ using namespace constitutive; /******************************** PerforationFluxKernel ********************************/ template< integer NC, integer NP, integer IS_THERMAL > -class PerforationFluxKernel : public isothermalPerforationFluxKernels::PerforationFluxKernel +class PerforationFluxKernel : public isothermalPerforationFluxKernels::PerforationFluxKernel< NC, NP, IS_THERMAL > { public: - using Base = isothermalPerforationFluxKernels::PerforationFluxKernel; + using Base = isothermalPerforationFluxKernels::PerforationFluxKernel< NC, NP, IS_THERMAL >; //using AbstractBase::m_dPhaseVolFrac; using Base::m_resPhaseCompFrac; using Base::m_dResCompFrac_dCompDens; @@ -866,7 +872,7 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati static constexpr integer isThermal = IS_THERMAL; using TAG = typename Base::TAG; - using CompFlowAccessors = typename Base::CompFlowAccessors ; + using CompFlowAccessors = typename Base::CompFlowAccessors; using MultiFluidAccessors = typename Base::MultiFluidAccessors; using RelPermAccessors = typename Base::RelPermAccessors; @@ -901,18 +907,18 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati RelPermAccessors const & relPermAccessors, bool const disableReservoirToWellFlow, ThermalCompFlowAccessors const & thermalCompFlowAccessors, - ThermalMultiFluidAccessors const & thermalMultiFluidAccessors) - : Base(perforationData, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors ) + : Base( perforationData, subRegion, compFlowAccessors, multiFluidAccessors, relPermAccessors, disableReservoirToWellFlow ), - m_stack(subRegion, + m_stack( subRegion, perforationData, fluid, thermalCompFlowAccessors, - thermalMultiFluidAccessors) + thermalMultiFluidAccessors ) //m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), //m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), @@ -936,12 +942,12 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati ThermalCompFlowAccessors const & thermalCompFlowAccessors, ThermalMultiFluidAccessors const & thermalMultiFluidAccessors ) : Base::StackVariables(), -m_wellElemPhaseVolFrac(subRegion.getField< fields::well::phaseVolumeFraction >()), + m_wellElemPhaseVolFrac( subRegion.getField< fields::well::phaseVolumeFraction >()), m_dPhaseVolFrac( subRegion.getField< fields::well::dPhaseVolumeFraction >() ), m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), - m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()) , - m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) , + m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), + m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()), m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) @@ -958,11 +964,11 @@ m_wellElemPhaseVolFrac(subRegion.getField< fields::well::phaseVolumeFraction >() arrayView3d< real64 > const & m_dEnergyPerfFlux; /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; + ElementViewConst< arrayView1d< real64 const > > const m_temp; /// Views on phase enthalpies - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseEnthalpy; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseEnthalpy; + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseEnthalpy; }; template< typename FUNC = NoOpFunc > @@ -971,7 +977,7 @@ m_wellElemPhaseVolFrac(subRegion.getField< fields::well::phaseVolumeFraction >() void computeFlux( localIndex const iperf ) const { - Base::computeFlux(iperf, m_stack ); + Base::computeFlux( iperf, m_stack ); } @@ -992,7 +998,7 @@ m_wellElemPhaseVolFrac(subRegion.getField< fields::well::phaseVolumeFraction >() forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) { //kernelComponent.setupStack(iperf); - kernelComponent.computeFlux(iperf); + kernelComponent.computeFlux( iperf ); } ); } @@ -1036,7 +1042,7 @@ class PerforationFluxKernelFactory ElementRegionManager & elemManager, integer const disableReservoirToWellFlow ) { - geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases , [&]( auto NC, auto NP ) + geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases, [&]( auto NC, auto NP ) { integer constexpr NUM_COMP = NC(); integer constexpr NUM_PHASE = NP(); @@ -1046,9 +1052,9 @@ class PerforationFluxKernelFactory typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); //typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, flowSolverName ); - typename kernelType::RelPermAccessors relPermAccessors( elemManager ,flowSolverName ); - typename kernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, flowSolverName ); - typename kernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, flowSolverName ); + typename kernelType::RelPermAccessors relPermAccessors( elemManager, flowSolverName ); + typename kernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, flowSolverName ); + typename kernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, flowSolverName ); //typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, flowSolverName ); //ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = // elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index bd625b2a2e5..e434664f51d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -316,13 +316,9 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 2 > } else { - normalizer = LvArray::math::max( m_minNormalizer, normalizer ); - // Step 4: compute the contribution to the residual - std::cout << "bNormalize " << idof << " " << stack.localRow + idof << " " << m_localResidual[stack.localRow + idof] << " " << normalizer << std::endl; real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; - std::cout << "Normalizer " << val << " " << stack.localValue[0] << std::endl; if( val > stack.localValue[0] ) { stack.localValue[0] = val; @@ -572,15 +568,12 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP]; real64 const dPhaseEnergy_dT = dPhaseAmount[FLUID_PROP_COFFSET::dT] * phaseInternalEnergy[ip] + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dT]; -std::cout << "wellthermaccum " << ip << " " << dPhaseAmount[FLUID_PROP_COFFSET::dT] << " " << phaseInternalEnergy[ip] - << " " << phaseAmount << " " << dPhaseInternalEnergy[ip][Deriv::dT] << std::endl; // local accumulation stack.localResidual[numEqn-1] += phaseEnergy - phaseEnergy_n; // derivatives w.r.t. pressure and temperature stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP; stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; -std::cout << "dPhaseEnergy ip " << ip << " dp " << stack.localJacobian[numEqn-1][0] << " dt " << stack.localJacobian[numEqn-1][numDof-1] << std::endl; // derivatives w.r.t. component densities applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); @@ -588,7 +581,6 @@ std::cout << "dPhaseEnergy ip " << ip << " dp " << stack.localJacobian[numEqn-1 { stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] + dPhaseInternalEnergy_dC[jc] * phaseAmount; -std::cout << "therm accu " << numEqn-1 << " " << jc+1 << " " << stack.localJacobian[numEqn-1][jc + 1] << std::endl; } } ); @@ -787,6 +779,13 @@ struct StackVariables : public Base::StackVariables stack.localEnergyFlux.resize( stack.numConnectedElems ); stack.localEnergyFluxJacobian.resize( stack.numConnectedElems, stack.stencilSize * numDof ); stack.localEnergyFluxJacobian_dQ.resize( stack.numConnectedElems, 1 ); + for( integer i=0; i= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.template addToRow< parallelDeviceAtomic >( eqnRowIndices[i], + &dofColIndices_dRate, + stack.localEnergyFluxJacobian_dQ[i], + 1 ); + m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices, + stack.localEnergyFluxJacobian[i], + CP_Deriv::nDer ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], stack.localEnergyFlux[i] ); + } + } + } } /** @@ -852,7 +895,6 @@ struct StackVariables : public Base::StackVariables real64 eflux_dq=0; for( integer ip = 0; ip < m_numPhases; ++ip ) { - std::cout << "eflux " << ip << " " << m_phaseEnthalpy[iwelemUp][0][ip] << " " << m_phaseFraction[iwelemUp][0][ip] << std::endl; eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; } @@ -870,8 +912,6 @@ struct StackVariables : public Base::StackVariables eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { - std::cout << " wellflux " << ip << " " << dof << " " << m_phaseEnthalpy[iwelemUp][0][ip] << " " << m_dPhaseFraction[iwelemUp][0][ip][dof] - << " " << m_dPhaseEnthalpy[iwelemUp][0][ip][dof] << " " << m_phaseFraction[iwelemUp][0][ip] << std::endl; stack.localEnergyFluxJacobian[0] [dof] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][dof] + m_dPhaseEnthalpy[iwelemUp][0][ip][dof]*m_phaseFraction[iwelemUp][0][ip]; @@ -894,8 +934,6 @@ struct StackVariables : public Base::StackVariables eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { - std::cout << " wellflux " << ip << " " << dof << " " << m_phaseEnthalpy[iwelemUp][0][ip] << " " << m_dPhaseFraction[iwelemUp][0][ip][dof] - << " " << m_dPhaseEnthalpy[iwelemUp][0][ip][dof] << " " << m_phaseFraction[iwelemUp][0][ip] << std::endl; stack.localEnergyFluxJacobian[TAG::NEXT ][dof] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][dof] + m_dPhaseEnthalpy[iwelemUp][0][ip][dof]*m_phaseFraction[iwelemUp][0][ip]; stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][dof] @@ -904,13 +942,12 @@ struct StackVariables : public Base::StackVariables } stack.localEnergyFlux[TAG::NEXT ] = m_dt * eflux * currentConnRate; stack.localEnergyFlux[TAG::CURRENT ] = -m_dt * eflux * currentConnRate; - stack.localEnergyFluxJacobian_dQ [TAG::NEXT ][0] = m_dt * eflux; stack.localEnergyFluxJacobian_dQ [TAG::CURRENT][0] = -m_dt * eflux; for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { - stack.localEnergyFluxJacobian[TAG::NEXT ][dof] = m_dt*currentConnRate; - stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] = -m_dt*currentConnRate; + stack.localEnergyFluxJacobian[TAG::NEXT ][dof] *= m_dt*currentConnRate; + stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] *= -m_dt*currentConnRate; } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp index 63747fa5687..ea1232cb7e4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp @@ -45,10 +45,10 @@ namespace thermalSinglePhaseWellKernels * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance */ template< integer NUM_DOF > -class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAssemblyKernel +class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAssemblyKernel< NUM_DOF > { public: - using Base = singlePhaseWellKernels::ElementBasedAssemblyKernel; + using Base = singlePhaseWellKernels::ElementBasedAssemblyKernel< NUM_DOF >; using Base::m_rankOffset; using Base::m_wellElemDofNumber; using Base::m_elemGhostRank; @@ -83,7 +83,7 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs constitutive::SingleFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ), + : Base( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ), m_dWellElemDensity_dTemperature( fluid.dDensity_dTemperature() ), m_internalEnergy( fluid.internalEnergy() ), m_internalEnergy_n( fluid.internalEnergy_n() ), @@ -124,7 +124,6 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs - /** * @brief Compute the local accumulation contributions to the residual and Jacobian * @tparam FUNC the type of the function that can be used to customize the kernel @@ -135,13 +134,13 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE void computeAccumulation( localIndex const iwelem, - StackVariables & stack) const + StackVariables & stack ) const { Base::computeAccumulation( iwelem, stack, [&]( ) { // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature - stack.localJacobian[0][numDof-1] = stack.volume * m_dWellElemDensity_dTemperature[iwelem][0] ; + stack.localJacobian[0][numDof-1] = stack.volume * m_dWellElemDensity_dTemperature[iwelem][0]; // Step 2: assemble the fluid part of the accumulation term of the energy equation real64 const fluidEnergy = stack.volume * stack.density * m_internalEnergy[iwelem][0]; @@ -164,7 +163,6 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs - /** * @brief Performs the kernel launch * @tparam POLICY the policy used in the RAJA kernels @@ -233,10 +231,10 @@ class ElementBasedAssemblyKernelFactory arrayView1d< real64 > const & localRhs ) { integer constexpr NUM_DOF = 2; - ElementBasedAssemblyKernel< NUM_DOF > + ElementBasedAssemblyKernel< NUM_DOF > kernel( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ); ElementBasedAssemblyKernel< NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< NUM_DOF > >( subRegion.size(), kernel ); + launch< POLICY, ElementBasedAssemblyKernel< NUM_DOF > >( subRegion.size(), kernel ); } }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp index cefaab8a4ea..86ff95983d3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp @@ -43,7 +43,7 @@ struct PotGrad template< integer NC, integer ISTHERMAL > GEOS_HOST_DEVICE static void - compute (real64 const & gravCoef, + compute ( real64 const & gravCoef, real64 const & gravCoefNext, real64 const & pres, real64 const & presNext, @@ -166,10 +166,10 @@ struct WellElementPhaseFlux real64 dGravHead_dP[numFluxSupportPoints]{}; real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; PotGrad::compute< numComp, IS_THERMAL >( gravCoef - ,gravCoefNext + , gravCoefNext , pres - ,presNext - ,totalMassDens + , presNext + , totalMassDens , totalMassDensNext , dTotalMassDens , dTotalMassDensNext diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 9e57353d8a7..7d0e9749fb8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -42,7 +42,7 @@ m_numPhases( 0 ), m_numComponents( 0 ), m_numDofPerWellElement( 0 ), m_numDofPerResElement( 0 ), - m_isThermal( false ), + m_isThermal( 0 ), m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" )) { this->getWrapper< string >( viewKeyStruct::discretizationString()).setInputFlag( InputFlags::FALSE ); @@ -52,8 +52,6 @@ m_numPhases( 0 ), setInputFlag( InputFlags::OPTIONAL ). setDescription( "Flag indicating whether the problem is thermal or not." ); - - } Group *WellSolverBase::createChild( string const & childKey, string const & childName ) diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index 109543d0b8c..f512a614286 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -441,7 +441,6 @@ arrayView4d< real64 const > const & dCompPerfRate = dofColIndices.data(), localPerfJacobian[i].dataIfContiguous(), 2 * resNumDofs ); -std::cout << " coupled R&W perf " << i << " " << eqnRowIndices[i] << " " << localPerf[i] << " " << localRhs[eqnRowIndices[i]] << std::endl; RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndices[i]], localPerf[i] ); } } diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index e4de48fa9ef..5f79bf67c5f 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -40,7 +40,7 @@ using namespace constitutive; * @tparam NUM_COMP number of fluid components * @brief Define the interface for the assembly kernel in charge of flux terms */ -template< integer NC , integer IS_THERMAL > +template< integer NC, integer IS_THERMAL > class IsothermalCompositionalMultiPhaseFluxKernel { public: @@ -62,7 +62,6 @@ class IsothermalCompositionalMultiPhaseFluxKernel - /// Compute time value for the number of degrees of freedom static constexpr integer numDof = WJ_COFFSET::nDer; @@ -93,22 +92,22 @@ class IsothermalCompositionalMultiPhaseFluxKernel arrayView1d< real64 > const & localRhs, CRSMatrixView< real64, globalIndex const > const & localMatrix, - bool const & detectCrossflow , + bool const & detectCrossflow, integer & numCrossFlowPerforations, BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) : m_dt( dt ), m_numPhases ( fluid.numFluidPhases()), - m_rankOffset(rankOffset), + m_rankOffset( rankOffset ), m_compPerfRate( perforationData->getField< fields::well::compPerforationRate >() ), m_dCompPerfRate_dPres( perforationData->getField< fields::well::dCompPerforationRate_dPres >() ), m_dCompPerfRate_dComp( perforationData->getField< fields::well::dCompPerforationRate_dComp >() ), - m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate>() ), - m_perfWellElemIndex( perforationData->getField< fields::perforation::wellElementIndex >() ), + m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate >() ), + m_perfWellElemIndex( perforationData->getField< fields::perforation::wellElementIndex >() ), m_wellElemDofNumber( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), m_resElemDofNumber( resDofNumber ), m_resElementRegion( perforationData->getField< fields::perforation::reservoirElementRegion >() ), - m_resElementSubRegion( perforationData->getField< fields::perforation::reservoirElementSubRegion >() ), + m_resElementSubRegion( perforationData->getField< fields::perforation::reservoirElementSubRegion >() ), m_resElementIndex( perforationData->getField< fields::perforation::reservoirElementIndex >() ), m_localRhs( localRhs ), m_localMatrix( localMatrix ), @@ -130,7 +129,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel GEOS_HOST_DEVICE inline void computeFlux( localIndex const iperf, - FUNC && compFluxKernelOp = NoOpFunc{} ) const + FUNC && compFluxKernelOp = NoOpFunc{} ) const { using namespace compositionalMultiphaseUtilities; @@ -181,7 +180,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel m_numCrossFlowPerforations += 1; } } - if ( 1 ) + if( 1 ) { for( integer ke = 0; ke < 2; ++ke ) @@ -213,8 +212,8 @@ class IsothermalCompositionalMultiPhaseFluxKernel { localIndex const localDofIndexComp = localDofIndexPres + jc + 1; assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] - m_dCompPerfRate_dComp[iperf][ke][ic][jc] ) < FLT_EPSILON ); - localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] ; - localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] ; + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; } if constexpr ( IS_THERMAL ) { @@ -242,7 +241,6 @@ class IsothermalCompositionalMultiPhaseFluxKernel dofColIndices.data(), localPerfJacobian[i].dataIfContiguous(), 2 * resNumDOF ); - std::cout << " coupled R&W perf " << i << " " << eqnRowIndices[i] << " " << localPerf[i] << " " << m_localRhs[eqnRowIndices[i]] << std::endl; RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); } } @@ -267,7 +265,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel GEOS_MARK_FUNCTION; forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) { - kernelComponent.computeFlux( ie); + kernelComponent.computeFlux( ie ); } ); } @@ -291,9 +289,9 @@ class IsothermalCompositionalMultiPhaseFluxKernel // Element region, subregion, index arrayView1d< globalIndex const > const m_wellElemDofNumber; ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const m_resElemDofNumber; - arrayView1d< localIndex const > const m_resElementRegion; - arrayView1d< localIndex const > const m_resElementSubRegion; - arrayView1d< localIndex const > const m_resElementIndex; + arrayView1d< localIndex const > const m_resElementRegion; + arrayView1d< localIndex const > const m_resElementSubRegion; + arrayView1d< localIndex const > const m_resElementIndex; // RHS and Jacobian arrayView1d< real64 > const m_localRhs; @@ -301,13 +299,13 @@ class IsothermalCompositionalMultiPhaseFluxKernel bool const m_detectCrossflow; integer & m_numCrossFlowPerforations; - integer const m_useTotalMassEquation; + integer const m_useTotalMassEquation; }; /** * @class FaceBasedAssemblyKernelFactory */ -class IsothermalCompositionalMultiPhaseFluxKernelFactory +class IsothermalCompositionalMultiPhaseFluxKernelFactory { public: @@ -335,7 +333,7 @@ class IsothermalCompositionalMultiPhaseFluxKernelFactory PerforationData const * const perforationData, MultiFluidBase const & fluid, integer const & useTotalMassEquation, - bool const & detectCrossflow , + bool const & detectCrossflow, integer & numCrossFlowPerforations, arrayView1d< real64 > const & localRhs, CRSMatrixView< real64, globalIndex const > const & localMatrix @@ -354,7 +352,7 @@ class IsothermalCompositionalMultiPhaseFluxKernelFactory using kernelType = IsothermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 0 >; - kernelType kernel( dt, rankOffset, wellDofKey, subRegion,resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); + kernelType kernel( dt, rankOffset, wellDofKey, subRegion, resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); kernelType::template launch< POLICY >( perforationData->size(), kernel ); } ); @@ -367,8 +365,8 @@ class IsothermalCompositionalMultiPhaseFluxKernelFactory * @tparam NUM_COMP number of fluid components * @brief Define the interface for the assembly kernel in charge of flux terms */ -template< integer NC , integer IS_THERMAL > -class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalMultiPhaseFluxKernel +template< integer NC, integer IS_THERMAL > +class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalMultiPhaseFluxKernel< NC, IS_THERMAL > { public: using Base = IsothermalCompositionalMultiPhaseFluxKernel< NC, IS_THERMAL >; @@ -394,7 +392,6 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional - /// Compute time value for the number of degrees of freedom static constexpr integer numDof = WJ_COFFSET::nDer; @@ -424,10 +421,10 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional MultiFluidBase const & fluid, arrayView1d< real64 > const & localRhs, CRSMatrixView< real64, globalIndex const > const & localMatrix, - bool const & detectCrossflow , + bool const & detectCrossflow, integer & numCrossFlowPerforations, BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) - : Base( dt, + : Base( dt, rankOffset, wellDofKey, subRegion, @@ -436,11 +433,11 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional fluid, localRhs, localMatrix, - detectCrossflow , + detectCrossflow, numCrossFlowPerforations, kernelFlags ), - m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()) , - m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) + m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), + m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) { } @@ -455,17 +452,17 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional GEOS_HOST_DEVICE inline - void computeFlux( localIndex const iperf ) const + void computeFlux( localIndex const iperf ) const { - Base::computeFlux( iperf ,[&] (globalIndex const & resOffset , + Base::computeFlux( iperf, [&] ( globalIndex const & resOffset, globalIndex const & wellElemOffset, - stackArray1d< globalIndex, 2*resNumDOF >& dofColIndices ) + stackArray1d< globalIndex, 2*resNumDOF > & dofColIndices ) { // local working variables and arrays - stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 ); + stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 ); - stackArray1d< real64, 2 * numComp > localPerf( 2 ); - stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2 , 2 * resNumDOF ); + stackArray1d< real64, 2 * numComp > localPerf( 2 ); + stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2, 2 * resNumDOF ); // equantion offsets - note res and well have different equation lineups @@ -486,11 +483,11 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional for( integer ic = 0; ic < numComp; ++ic ) { localIndex const localDofIndexComp = localDofIndexPres + ic + 1; - localPerfJacobian[TAG::RES ][localDofIndexComp] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic] ; - localPerfJacobian[TAG::WELL][localDofIndexComp] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic] ; + localPerfJacobian[TAG::RES ][localDofIndexComp] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic]; + localPerfJacobian[TAG::WELL][localDofIndexComp] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic]; } - localPerfJacobian[TAG::RES ][localDofIndexPres+NC+1] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT] ; - localPerfJacobian[TAG::WELL][localDofIndexPres+NC+1] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT] ; + localPerfJacobian[TAG::RES ][localDofIndexPres+NC+1] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT]; + localPerfJacobian[TAG::WELL][localDofIndexPres+NC+1] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT]; } @@ -502,11 +499,10 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional dofColIndices.data(), localPerfJacobian[i].dataIfContiguous(), 2 * resNumDOF ); - std::cout << " coupled R&W perf " << i << " " << eqnRowIndices[i] << " " << localPerf[i] << " " << m_localRhs[eqnRowIndices[i]] << std::endl; RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); } } - }); + } ); } @@ -528,7 +524,7 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional GEOS_MARK_FUNCTION; forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie ) { - kernelComponent.computeFlux( ie); + kernelComponent.computeFlux( ie ); } ); } @@ -536,8 +532,8 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositional protected: /// Views on energy flux - arrayView1d< real64 const > const m_energyPerfFlux; - arrayView3d< real64 const > const m_dEnergyPerfFlux; + arrayView1d< real64 const > const m_energyPerfFlux; + arrayView3d< real64 const > const m_dEnergyPerfFlux; }; /** @@ -571,7 +567,7 @@ class ThermalCompositionalMultiPhaseFluxKernelFactory PerforationData const * const perforationData, MultiFluidBase const & fluid, integer const & useTotalMassEquation, - bool const & detectCrossflow , + bool const & detectCrossflow, integer & numCrossFlowPerforations, arrayView1d< real64 > const & localRhs, CRSMatrixView< real64, globalIndex const > const & localMatrix @@ -590,7 +586,7 @@ class ThermalCompositionalMultiPhaseFluxKernelFactory using kernelType = ThermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 1 >; - kernelType kernel( dt, rankOffset, wellDofKey, subRegion,resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); + kernelType kernel( dt, rankOffset, wellDofKey, subRegion, resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); kernelType::template launch< POLICY >( perforationData->size(), kernel ); } ); From 8b10201900480bab8e348e016d4e66e7d1d36975 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Mon, 13 May 2024 16:35:17 -0700 Subject: [PATCH 15/71] 1) Added simple temperature constraint 2) Fixes from running numerical derivative checker and treating warnings as errors --- .../finiteVolume/FluxApproximationBase.hpp | 1 - .../fluidFlow/CompositionalMultiphaseFVM.cpp | 6 +- .../CompositionalMultiphaseHybridFVM.cpp | 6 - ...rmalCompositionalMultiphaseBaseKernels.hpp | 2 - ...rmalCompositionalMultiphaseBaseKernels.hpp | 2 + .../wells/CompositionalMultiphaseWell.cpp | 149 +++++++++++++++--- .../wells/CompositionalMultiphaseWell.hpp | 2 +- .../CompositionalMultiphaseWellKernels.cpp | 9 +- .../CompositionalMultiphaseWellKernels.hpp | 47 +++++- .../wells/PerforationFluxKernels.hpp | 15 +- .../fluidFlow/wells/SinglePhaseWell.cpp | 2 +- .../fluidFlow/wells/SinglePhaseWell.hpp | 2 +- .../wells/SinglePhaseWellKernels.hpp | 6 +- .../fluidFlow/wells/WellSolverBase.cpp | 12 +- .../fluidFlow/wells/WellSolverBase.hpp | 2 +- .../fluidFlow/wells/WellSolverBaseFields.hpp | 4 +- ...mpositionalMultiphaseReservoirAndWells.cpp | 6 +- .../CoupledReservoirAndWellKernels.hpp | 2 +- 18 files changed, 213 insertions(+), 62 deletions(-) diff --git a/src/coreComponents/finiteVolume/FluxApproximationBase.hpp b/src/coreComponents/finiteVolume/FluxApproximationBase.hpp index ffb974945fa..a26320b39c3 100644 --- a/src/coreComponents/finiteVolume/FluxApproximationBase.hpp +++ b/src/coreComponents/finiteVolume/FluxApproximationBase.hpp @@ -333,7 +333,6 @@ void FluxApproximationBase::forStencils( MeshLevel const & mesh, LAMBDA && lambd Group const & stencilGroup = mesh.getGroup( groupKeyStruct::stencilMeshGroupString() ).getGroup( getName() ); stencilGroup.forWrappers< TYPE, TYPES... >( [&] ( auto const & wrapper ) { - std::cout << "FluxApproximationBase::forStencils " << wrapper.getName() << std::endl; lambda( wrapper.reference() ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp index 823a7d2b1c2..f564cb5260a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp @@ -515,11 +515,9 @@ real64 CompositionalMultiphaseFVM::scalingForSystemSolution( DomainPartition & d m_maxAbsolutePresChange, m_maxCompFracChange, pressure, - temperature, compDens, pressureScalingFactor, compDensScalingFactor, - temperatureScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, @@ -665,10 +663,10 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; if( numNegDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative component density values: {}, minimum value: {} {}}", + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative component density values: {}, minimum value: {} {} ", getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); if( minTotalDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative total density values: {}, minimum value: {} {}}", + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative total density values: {}, minimum value: {} {} ", getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); return MpiWrapper::min( localCheck ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp index 2f6ec3dd60c..b8e1d3f9d0f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp @@ -445,10 +445,8 @@ real64 CompositionalMultiphaseHybridFVM::scalingForSystemSolution( DomainPartiti ElementSubRegionBase & subRegion ) { arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temperature = subRegion.getField< fields::flow::temperature >(); arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); - arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::flow::temperatureScalingFactor >(); arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); auto const subRegionData = isothermalCompositionalMultiphaseBaseKernels:: @@ -457,11 +455,9 @@ real64 CompositionalMultiphaseHybridFVM::scalingForSystemSolution( DomainPartiti m_maxAbsolutePresChange, m_maxCompFracChange, pressure, - temperature, compDens, pressureScalingFactor, compDensScalingFactor, - temperatureScalingFactor, dofManager.rankOffset(), m_numComponents, dofKey, @@ -530,8 +526,6 @@ bool CompositionalMultiphaseHybridFVM::checkSystemSolution( DomainPartition & do { arrayView1d< real64 const > const pressure = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temperature = - subRegion.getField< fields::flow::temperature >(); arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::flow::globalCompDensity >(); arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::flow::pressureScalingFactor >(); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp index b3f531f5e18..621b0934e7a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp @@ -1473,11 +1473,9 @@ class ScalingForSystemSolutionKernelFactory real64 const maxAbsolutePresChange, real64 const maxCompFracChange, arrayView1d< real64 const > const pressure, - arrayView1d< real64 const > const temperature, arrayView2d< real64 const, compflow::USD_COMP > const compDens, arrayView1d< real64 > pressureScalingFactor, arrayView1d< real64 > compDensScalingFactor, - arrayView1d< real64 > temperatureScalingFactor, globalIndex const rankOffset, integer const numComp, string const dofKey, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp index 4b667c9ac63..8350de99447 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp @@ -333,11 +333,13 @@ class ElementBasedAssemblyKernel : public isothermalCompositionalMultiphaseBaseK stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; // derivatives w.r.t. component densities + //std::cout << "res " << dPhaseInternalEnergy[ip][Deriv::dC] << " " << dPhaseInternalEnergy[ip][Deriv::dC+1] << std::endl; applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); for( integer jc = 0; jc < numComp; ++jc ) { stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount_dC[jc] + dPhaseInternalEnergy_dC[jc] * phaseAmount; + //std::cout << "phase " << ip << " jc " << jc << " " << stack.localJacobian[numEqn-1][jc + 1] << std::endl; } } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 3a66d02011f..f4e6315be6e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1016,7 +1016,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - integer const useTotalMassEquation = 1; + string const wellDofKey = dofManager.getKey( wellElementDofName()); if( 1 ) { @@ -1042,7 +1042,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, dofManager.rankOffset(), - useTotalMassEquation, + m_useTotalMassEquation, wellDofKey, subRegion, fluid, @@ -1056,7 +1056,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, dofManager.rankOffset(), - useTotalMassEquation, + m_useTotalMassEquation, wellDofKey, subRegion, fluid, @@ -1108,7 +1108,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, createAndLaunch< parallelDevicePolicy<> >( numComponents, dt, dofManager.rankOffset(), - useTotalMassEquation, + m_useTotalMassEquation, wellDofKey, well_controls, subRegion, @@ -1123,7 +1123,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, createAndLaunch< parallelDevicePolicy<> >( numComponents, dt, dofManager.rankOffset(), - useTotalMassEquation, + m_useTotalMassEquation, wellDofKey, well_controls, subRegion, @@ -1143,20 +1143,15 @@ void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & s // update volumetric rates for the well constraints // note: this must be called before updateFluidModel - updateVolRatesForConstraint( subRegion ); // tjb - thermal +++ looks like it does a lot more... + updateVolRatesForConstraint( subRegion ); // update densities, phase fractions, phase volume fractions - updateFluidModel( subRegion ); // Calculate fluid properties - - updatePhaseVolumeFraction( subRegion ); // tjb - thermal - - updateTotalMassDensity( subRegion ); // tjb - thermal - + updateFluidModel( subRegion ); // Calculate fluid properties; + updatePhaseVolumeFraction( subRegion ); + updateTotalMassDensity( subRegion ); // update the current BHP pressure updateBHPForConstraint( subRegion ); - - // note: the perforation rates are updated separately } void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain ) @@ -1274,13 +1269,15 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain ) } void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, - DomainPartition const & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; + if( 0 ) + { // loop over the wells forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & mesh, @@ -1324,6 +1321,55 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, localRhs ); } ); } ); + } + else + { + string const wellDofKey = dofManager.getKey( wellElementDofName()); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + WellControls const & well_controls = getWellControls( subRegion ); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numComponents = fluid.numFluidComponents(); + + if( isThermal() ) + { + thermalCompositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + localMatrix, + localRhs ); + } + } ); + } ); + } } void CompositionalMultiphaseWell::assembleAccumulationTerms( DomainPartition const & domain, @@ -1332,7 +1378,71 @@ DofManager const & dofManager, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion const & subRegion ) + { + + // get the degrees of freedom and ghosting info + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); + + // get the properties on the well element + arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac = + subRegion.getField< fields::well::phaseVolumeFraction >(); + arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac = + subRegion.getField< fields::well::dPhaseVolumeFraction >(); + arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = + subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); + + arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n = + subRegion.getField< fields::well::phaseVolumeFraction_n >(); + + arrayView1d< real64 const > const & wellElemVolume = subRegion.getElementVolume(); + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens = fluid.dPhaseDensity(); + arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac = fluid.phaseCompFraction(); + arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac = fluid.dPhaseCompFraction(); + arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n = fluid.phaseDensity_n(); + arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n = fluid.phaseCompFraction_n(); + + isothermalCompositionalMultiphaseBaseKernels:: + KernelLaunchSelector1< AccumulationKernel >( numFluidComponents(), + subRegion.size(), + numFluidPhases(), + dofManager.rankOffset(), + m_useTotalMassEquation, + wellElemDofNumber, + wellElemGhostRank, + wellElemVolume, + wellElemPhaseVolFrac, + dWellElemPhaseVolFrac, + dWellElemCompFrac_dCompDens, + wellElemPhaseDens, + dWellElemPhaseDens, + wellElemPhaseCompFrac, + dWellElemPhaseCompFrac, + wellElemPhaseVolFrac_n, + wellElemPhaseDens_n, + wellElemPhaseCompFrac_n, + localMatrix, + localRhs ); + } ); + } ); } @@ -1673,11 +1783,9 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, m_maxAbsolutePresChange, m_maxCompFracChange, pressure, - temperature, compDens, pressureScalingFactor, compDensScalingFactor, - temperatureScalingFactor, dofManager.rankOffset(), m_numComponents, wellDofKey, @@ -1752,12 +1860,9 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, { arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); - arrayView1d< real64 const > const temperature = - subRegion.getField< fields::well::temperature >(); arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >(); arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); - arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); auto const subRegionData = @@ -1875,10 +1980,10 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) ); string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; if( numNegDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative well component density values: {}, minimum value: {} {}}", + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative well component density values: {}, minimum value: {} {} ", getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); if( minTotalDens > 0 ) - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative total well density values: {}, minimum value: {} {}}", + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Number of negative total well density values: {}, minimum value: {} {} ", getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 1a711f7d520..c91326c7911 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -216,7 +216,7 @@ virtual void assembleSystem( real64 const time, * @param rhs the system right-hand side vector */ virtual void assembleFluxTerms( real64 const dt, - DomainPartition const & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index e2b6b47a3c1..b83c72873e0 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -1953,10 +1953,17 @@ PresTempCompFracInitializationKernel:: } // for an injector, we use the injection stream values else + { + if( wellControls.useSurfaceConditions() ) + { + // use surface temperature from injection stream + avgTemp = wellControls.getSurfaceTemperature(); + } + else { // use temperature from injection stream avgTemp = wellControls.getInjectionTemperature(); - + } // use comp frac from injection stream for( integer ic = 0; ic < numComps; ++ic ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 9c037212727..518e75885fc 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -1093,7 +1093,7 @@ class ElementBasedAssemblyKernel /// Number of Dof's set in this kernal - no dQ in accum static constexpr integer numDof = NUM_COMP + 1 + IS_THERMAL; - /// Compute time value for the number of equations + /// Compute time value for the number of equations mass bal + vol bal + energy bal static constexpr integer numEqn = NUM_COMP + 1 + IS_THERMAL; @@ -1109,6 +1109,7 @@ class ElementBasedAssemblyKernel * @param[inout] localRhs the local right-hand side vector */ ElementBasedAssemblyKernel( localIndex const numPhases, + integer const isProducer, globalIndex const rankOffset, string const dofKey, ElementSubRegionBase const & subRegion, @@ -1117,6 +1118,7 @@ class ElementBasedAssemblyKernel arrayView1d< real64 > const & localRhs, BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) : m_numPhases( numPhases ), + m_isProducer( isProducer ), m_rankOffset( rankOffset ), m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), m_elemGhostRank( subRegion.ghostRank() ), @@ -1398,11 +1400,33 @@ if constexpr ( IS_THERMAL ) * @param[inout] stack the stack variables */ GEOS_HOST_DEVICE - void complete( localIndex const GEOS_UNUSED_PARAM( ei ), + void complete( localIndex const ei, //GEOS_UNUSED_PARAM( ei ), StackVariables & stack ) const { using namespace compositionalMultiphaseUtilities; + integer const numRows = numComp+1+ IS_THERMAL; + + if constexpr (IS_THERMAL) + { + if( ei == 0 && !m_isProducer ) + { + // For top segment energy balance eqn replaced with T(n+1) - T = 0 + // No other energy balance derivatives + // Assumption is iwelem =0 is top segment with fixed temp BC + + for( integer i=0; i < numComp+1+IS_THERMAL; i++ ) + { + stack.localJacobian[numRows-1][i] = 0.0; + } + // constant Temperature + for( integer i=0; i < numComp+1+IS_THERMAL; i++ ) + stack.localJacobian[i][numRows-1] = 0.0; + stack.localJacobian[numRows-1][numRows-1] = 1.0; + + stack.localResidual[numRows-1]=0.0; + } + } if( m_kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) { @@ -1416,7 +1440,7 @@ if constexpr ( IS_THERMAL ) // - the component mass balance equations (i = 0 to i = numComp-1) // - the volume balance equations (i = numComp) // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - integer const numRows = numComp+1+ IS_THERMAL; + for( integer i = 0; i < numRows; ++i ) { m_localRhs[stack.eqnRowIndices[i]] += stack.localResidual[i]; @@ -1463,6 +1487,9 @@ if constexpr ( IS_THERMAL ) /// Number of fluid phases integer const m_numPhases; + /// Well type + integer const m_isProducer; + /// Offset for my MPI rank globalIndex const m_rankOffset; @@ -1533,6 +1560,7 @@ class ElementBasedAssemblyKernelFactory static void createAndLaunch( localIndex const numComps, localIndex const numPhases, + integer const isProducer, globalIndex const rankOffset, integer const useTotalMassEquation, string const dofKey, @@ -1544,7 +1572,7 @@ class ElementBasedAssemblyKernelFactory geos::internal::kernelLaunchSelectorCompThermSwitch( numComps, 0, [&]( auto NC, auto IS_THERMAL ) { localIndex constexpr NUM_COMP = NC(); - localIndex constexpr NUM_DOF = NC()+2; + integer constexpr istherm = IS_THERMAL(); BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; @@ -1552,7 +1580,7 @@ integer constexpr istherm = IS_THERMAL(); kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); ElementBasedAssemblyKernel< NUM_COMP, istherm > - kernel( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); + kernel( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); ElementBasedAssemblyKernel< NUM_COMP, istherm >::template launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, istherm > >( subRegion.size(), kernel ); } ); @@ -1698,6 +1726,7 @@ class FaceBasedAssemblyKernel void complete( localIndex const iconn, StackVariables & stack ) const { + GEOS_UNUSED_VAR( iconn ); using namespace compositionalMultiphaseUtilities; if( stack.numConnectedElems ==1 ) { @@ -1945,6 +1974,7 @@ class FaceBasedAssemblyKernel real64 dCompFlux_dPresUp[NC]{}; real64 dCompFlux_dCompDensUp[NC][NC]{}; + real64 dComp[NC][NC]; real64 dCompFlux[NC][numDof]{}; // Step 1) decide the upwind well element @@ -1970,6 +2000,11 @@ class FaceBasedAssemblyKernel for( integer jc = 0; jc < NC; ++jc ) { dCompFrac_dCompDensUp[ic][jc] = 0.0; + dComp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + } + //for ( integer jc = 0 ;jc < WJ_COFFSET::nDer ; ++jc) + for( integer jc = 0; jc < NC; ++jc ) + { dCompFlux[ic][WJ_COFFSET::dC+jc] = 0.0; } } @@ -2161,7 +2196,7 @@ stack.offsetNext = m_wellElemDofNumber[iwelemNext]; */ } - compFluxKernelOp( iwelemNext, iwelemUp, currentConnRate ); + compFluxKernelOp( iwelemNext, iwelemUp, currentConnRate, dComp ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index 424883a8991..ccc0047828e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -687,19 +687,24 @@ bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy; stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy; - // energy equation derivatives WRT well P & T stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dP] - + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dP]; - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][Deriv::dT] * wellelem_enthalpy + + pflux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dP]; + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dT] + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dT]; - //energy equation + //energy e + real64 dPVF_dC[numComp]{}; + applyChainRule( NC, + m_dWellElemCompFrac_dCompDens[iwelem], + stack.m_dPhaseVolFrac[iwelem][ip], + dPVF_dC, + Deriv::dC ); for( integer ic=0; ic const & localMatrix, arrayView1d< real64 > const & localRhs ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 4c3ea81271e..3e818eebb05 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -177,7 +177,7 @@ class SinglePhaseWell : public WellSolverBase * @param rhs the system right-hand side vector */ void assembleFluxTerms( real64 const dt, - DomainPartition const & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp index 025044d59bb..8bd0607946a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp @@ -663,9 +663,9 @@ class ElementBasedAssemblyKernel StackVariables & stack, FUNC && KernelOp = NoOpFunc{} ) const { - - localIndex const eqnRowIndex = m_wellElemDofNumber[iwelem] + ROFFSET::MASSBAL - m_rankOffset; - globalIndex const presDofColIndex = m_wellElemDofNumber[iwelem] + COFFSET::DPRES; + GEOS_UNUSED_VAR( iwelem ); + //localIndex const eqnRowIndex = m_wellElemDofNumber[iwelem] + ROFFSET::MASSBAL - m_rankOffset; + //globalIndex const presDofColIndex = m_wellElemDofNumber[iwelem] + COFFSET::DPRES; stack.localResidual[0] = stack.volume * ( stack.density - stack.density_n ); stack.localJacobian[0][1] = stack.volume * stack.dDensity_dPres; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 7d0e9749fb8..6cca7f72dd6 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -197,6 +197,8 @@ void WellSolverBase::assembleSystem( real64 const time, [&]( localIndex const, WellElementSubRegion & subRegion ) { + WellControls const & well_controls = getWellControls( subRegion ); + integer isProducer = well_controls.isProducer(); string const dofKey = dofManager.getKey( CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString()); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); @@ -208,6 +210,7 @@ void WellSolverBase::assembleSystem( real64 const time, ElementBasedAssemblyKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, + isProducer, dofManager.rankOffset(), useTotalMassEquation, wellDofKey, @@ -231,7 +234,8 @@ void WellSolverBase::assembleSystem( real64 const time, [&]( localIndex const, WellElementSubRegion & subRegion ) { - + WellControls const & well_controls = getWellControls( subRegion ); + integer isProducer = well_controls.isProducer(); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); @@ -242,6 +246,7 @@ void WellSolverBase::assembleSystem( real64 const time, ElementBasedAssemblyKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, + isProducer, dofManager.rankOffset(), useTotalMassEquation, wellDofKey, @@ -278,7 +283,8 @@ void WellSolverBase::assembleSystem( real64 const time, [&]( localIndex const, WellElementSubRegion & subRegion ) { - + WellControls const & well_controls = getWellControls( subRegion ); + integer isProducer = well_controls.isProducer(); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); int numPhases = fluid.numFluidPhases(); @@ -290,6 +296,7 @@ void WellSolverBase::assembleSystem( real64 const time, ElementBasedAssemblyKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, + isProducer, dofManager.rankOffset(), useTotalMassEquation, wellDofKey, @@ -304,6 +311,7 @@ void WellSolverBase::assembleSystem( real64 const time, ElementBasedAssemblyKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, + isProducer, dofManager.rankOffset(), useTotalMassEquation, wellDofKey, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index aa1c7335426..3f8c3ba2c43 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -197,7 +197,7 @@ class WellSolverBase : public SolverBase * @param rhs the system right-hand side vector */ virtual void assembleFluxTerms( real64 const dt, - DomainPartition const & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp index ad9a099508e..e1e31e61144 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp @@ -49,7 +49,7 @@ DECLARE_FIELD( pressure_n, "Pressure at the previous converged time step" ); DECLARE_FIELD( temperature, - "wellTemperature", + "temperature", array1d< real64 >, 0, LEVEL_0, @@ -57,7 +57,7 @@ DECLARE_FIELD( temperature, "Temperature" ); DECLARE_FIELD( temperature_n, - "wellTemperature_n", + "temperature_n", array1d< real64 >, 0, NOPLOT, diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index f512a614286..5fa587e4515 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -347,8 +347,8 @@ areWellsShut = 0; perforationData->getField< fields::well::dCompPerforationRate_dPres >(); arrayView4d< real64 const > const & dCompPerfRate_dComp = perforationData->getField< fields::well::dCompPerforationRate_dComp >(); -arrayView4d< real64 const > const & dCompPerfRate = - perforationData->getField< fields::well::dCompPerforationRate >(); + //arrayView4d< real64 const > const & dCompPerfRate = + // perforationData->getField< fields::well::dCompPerforationRate >(); arrayView1d< localIndex const > const & perfWellElemIndex = perforationData->getField< fields::perforation::wellElementIndex >(); @@ -465,7 +465,7 @@ arrayView4d< real64 const > const & dCompPerfRate = { integer useTotalMassEquation1=1; integer numCrossflowPerforations=0; - if( isThermal ( ) ) + if( isThermal ( ) ) { coupledReservoirAndWellKernels:: ThermalCompositionalMultiPhaseFluxKernelFactory:: diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 5f79bf67c5f..3fc0ef3a5c2 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -180,7 +180,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel m_numCrossFlowPerforations += 1; } } - if( 1 ) + if( 0 ) { for( integer ke = 0; ke < 2; ++ke ) From 25e35031e79b1f0ad80619e2d6fb395f07166f87 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 14 May 2024 09:21:36 -0700 Subject: [PATCH 16/71] missing merge in previous commit --- ...rmalCompositionalMultiphaseWellKernels.hpp | 117 ++++++++++++++---- 1 file changed, 92 insertions(+), 25 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index e434664f51d..2b0a4da3ef4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -479,6 +479,7 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El * @param[inout] localRhs the local right-hand side vector */ ElementBasedAssemblyKernel( localIndex const numPhases, + integer const isProducer, globalIndex const rankOffset, string const dofKey, ElementSubRegionBase const & subRegion, @@ -486,7 +487,7 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) - : Base( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ), + : Base( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ), m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n()), m_phaseInternalEnergy( fluid.phaseInternalEnergy()), m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy()) @@ -605,18 +606,10 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El void complete( localIndex const ei, StackVariables & stack ) const { - // Step 1: assemble the component mass balance equations and volume balance equations + // Assemble the component mass balance equations and volume balance equations + // Energy balance equation updates to solver matrices included in Base class Base::complete( ei, stack ); - - /* fix me tjb - // Step 2: assemble the energy equation - m_localRhs[stack.localRow + numEqn - 1] += stack.localResidual[numEqn - 1]; - m_localMatrix.template addToRow(stack.localRow + numEqn - 1, - stack.dofIndices, - stack.localJacobian[numEqn - 1], - numDof); - */ } protected: @@ -652,6 +645,7 @@ class ElementBasedAssemblyKernelFactory static void createAndLaunch( localIndex const numComps, localIndex const numPhases, + integer const isProducer, globalIndex const rankOffset, integer const useTotalMassEquation, string const dofKey, @@ -671,7 +665,7 @@ class ElementBasedAssemblyKernelFactory kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); ElementBasedAssemblyKernel< NUM_COMP > - kernel( numPhases, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); + kernel( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); ElementBasedAssemblyKernel< NUM_COMP >::template launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP > >( subRegion.size(), kernel ); } ); @@ -792,10 +786,24 @@ struct StackVariables : public Base::StackVariables inline void complete( localIndex const iwelem, StackVariables & stack ) const { + Base::complete ( iwelem, stack ); + using namespace compositionalMultiphaseUtilities; if( stack.numConnectedElems ==1 ) { + if( !m_isProducer ) + { + // For top segment energy balance eqn replaced with T(n+1) - T = 0 + // No other energy balance derivatives + // Assumption is iwelem =0 is top segment with fixed temp BC + for( integer i=0; i< CP_Deriv::nDer; i++ ) + { + stack.localEnergyFluxJacobian[0][i] = 0.0; + } + stack.localEnergyFluxJacobian_dQ[0][0]=0; + stack.localEnergyFlux[0]=0; + } // Setup Jacobian global row indicies for energy equation globalIndex oneSidedEqnRowIndices = stack.offsetUp + WJ_ROFFSET::ENERGYBAL - m_rankOffset; @@ -828,6 +836,17 @@ struct StackVariables : public Base::StackVariables } else // if ( stack.numConnectedElems == 2 ) { + if( iwelem == 1 && !m_isProducer ) + { + // For top segment energy balance eqn replaced with T(n+1) - T = 0 + // No upstream energy balance derivatives added to segment with control + // Assumption is iwelem =0 is top segment with fixed temp BC + for( integer i=0; i Date: Tue, 14 May 2024 10:09:13 -0700 Subject: [PATCH 17/71] more merge fixes --- .../fluidFlow/wells/CompositionalMultiphaseWell.cpp | 5 ++++- .../wells/ThermalCompositionalMultiphaseWellKernels.hpp | 6 ------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index f4e6315be6e..88a7e422a29 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1034,6 +1034,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); int numPhases = fluid.numFluidPhases(); int numComponents = fluid.numFluidComponents(); + WellControls const & wellControls = getWellControls( subRegion ); if( isThermal() ) { @@ -1041,6 +1042,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, ElementBasedAssemblyKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, + wellControls.isProducer(), dofManager.rankOffset(), m_useTotalMassEquation, wellDofKey, @@ -1055,6 +1057,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, ElementBasedAssemblyKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( numComponents, numPhases, + wellControls.isProducer(), dofManager.rankOffset(), m_useTotalMassEquation, wellDofKey, @@ -1793,7 +1796,7 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, localSolution ); - scalingFactor = scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); + scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); maxDeltaPres = std::max( maxDeltaPres, subRegionData.localMaxDeltaPres ); maxDeltaCompDens = std::max( maxDeltaCompDens, subRegionData.localMaxDeltaCompDens ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 2b0a4da3ef4..6b7aef1b453 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -551,12 +551,6 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El // construct the slices arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy_n = m_phaseInternalEnergy_n[ei][0]; arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseInternalEnergy = m_dPhaseInternalEnergy[ei][0]; From c9138c50cf1ba53245c5f2efe460def8456e52ab Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Fri, 24 May 2024 10:08:07 -0700 Subject: [PATCH 18/71] 1) add iterative solver config for thermal res+well 2) skip well calcs for shutin well 3) call well initialization code for wells that come online at t> 0 --- .../linearAlgebra/CMakeLists.txt | 1 + .../interfaces/hypre/HypreMGR.cpp | 6 + ...malCompositionalMultiphaseReservoirFVM.hpp | 122 ++++++++++++++++++ .../utilities/LinearSolverParameters.hpp | 2 + .../wells/CompositionalMultiphaseWell.cpp | 106 ++++++++++++--- .../wells/CompositionalMultiphaseWell.hpp | 20 ++- .../CompositionalMultiphaseWellKernels.cpp | 4 + .../CompositionalMultiphaseWellKernels.hpp | 2 +- .../wells/PerforationFluxKernels.hpp | 9 +- .../fluidFlow/wells/SinglePhaseWell.cpp | 69 +++++++++- .../fluidFlow/wells/SinglePhaseWell.hpp | 16 ++- ...rmalCompositionalMultiphaseWellKernels.hpp | 2 +- .../wells/ThermalSinglePhaseWellKernels.hpp | 1 + .../fluidFlow/wells/WellControls.cpp | 2 + .../fluidFlow/wells/WellSolverBase.cpp | 91 ++++++++++--- .../fluidFlow/wells/WellSolverBase.hpp | 34 ++++- ...mpositionalMultiphaseReservoirAndWells.cpp | 10 +- .../CoupledReservoirAndWellKernels.hpp | 18 ++- 18 files changed, 447 insertions(+), 68 deletions(-) create mode 100644 src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp diff --git a/src/coreComponents/linearAlgebra/CMakeLists.txt b/src/coreComponents/linearAlgebra/CMakeLists.txt index 8e86dbfdd05..a1c9cda1c95 100644 --- a/src/coreComponents/linearAlgebra/CMakeLists.txt +++ b/src/coreComponents/linearAlgebra/CMakeLists.txt @@ -108,6 +108,7 @@ if( ENABLE_HYPRE ) interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp + interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp ) list( APPEND linearAlgebra_sources diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp index b41b7e9577a..a8cae1d4a62 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/HypreMGR.cpp @@ -36,6 +36,7 @@ #include "linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirFVM.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/SinglePhaseReservoirHybridFVM.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseFVM.hpp" +#include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalSinglePhasePoromechanics.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/ThermalMultiphasePoromechanics.hpp" #include "linearAlgebra/interfaces/hypre/mgrStrategies/SolidMechanicsEmbeddedFractures.hpp" @@ -104,6 +105,11 @@ void hypre::mgr::createMGR( LinearSolverParameters const & params, setStrategy< ThermalCompositionalMultiphaseFVM >( params.mgr, numComponentsPerField, precond, mgrData ); break; } + case LinearSolverParameters::MGR::StrategyType::thermalCompositionalMultiphaseReservoirFVM: + { + setStrategy< ThermalCompositionalMultiphaseReservoirFVM >( params.mgr, numComponentsPerField, precond, mgrData ); + break; + } case LinearSolverParameters::MGR::StrategyType::hybridSinglePhasePoromechanics: { setStrategy< HybridSinglePhasePoromechanics >( params.mgr, numComponentsPerField, precond, mgrData ); diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp new file mode 100644 index 00000000000..992b3c49ef0 --- /dev/null +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp @@ -0,0 +1,122 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalCompositionalMultiphaseFVM.hpp + */ + +#ifndef GEOS_LINEARALGEBRA_INTERFACES_HYPREMGRTHERMALCOMPOSITIONALMULTIPHASERESERVOIRFVM_HPP_ +#define GEOS_LINEARALGEBRA_INTERFACES_HYPREMGRTHERMALCOMPOSITIONALMULTIPHASERESERVOIRFVM_HPP_ + +#include "linearAlgebra/interfaces/hypre/HypreMGR.hpp" + +namespace geos +{ + +namespace hypre +{ + +namespace mgr +{ + +/** + * @brief ThermalCompositionalMultiphaseReservoirFVM strategy. + * + * Labels description stored in point_marker_array + * 0 = pressure + * 1 = density + * ... = densities + * numLabels - 2 = last density + * numLabels - 1 = temperature + * + * 2-level MGR reduction strategy + * - 1st level: eliminate the reservoir density associated with the volume constraint + * - 2nd level: eliminate the other reservoir densities + * - The coarse grid (pressure and temperature system) is solved with BoomerAMG with numFunctions==2. + * + */ +class ThermalCompositionalMultiphaseReservoirFVM : public MGRStrategyBase< 3 > +{ +public: + /** + * @brief Constructor. + * @param numComponentsPerField array with number of components for each field + */ + explicit ThermalCompositionalMultiphaseReservoirFVM( arrayView1d< int const > const & numComponentsPerField ) + : MGRStrategyBase( LvArray::integerConversion< HYPRE_Int >( numComponentsPerField[0] + numComponentsPerField[1] ) ) + { + HYPRE_Int const numResLabels = LvArray::integerConversion< HYPRE_Int >( numComponentsPerField[0] ); + + // Level 0: eliminate the well block + m_labels[0].resize( numResLabels ); + std::iota( m_labels[0].begin(), m_labels[0].end(), 0 ); + + // Level 1: eliminate last density which corresponds to the volume constraint equation + m_labels[1].resize( numResLabels - 2 ); + std::iota( m_labels[1].begin(), m_labels[1].end(), 0 ); + m_labels[1].push_back( numResLabels-1 ); // keep temperature + // Level 2: eliminate the other densities + m_labels[2].push_back( 0 ); // keep pressure + m_labels[2].push_back( numResLabels-1 ); // keep temperature + + setupLabels(); + + // level 0 + m_levelFRelaxType[0] = MGRFRelaxationType::gsElimWInverse; + m_levelFRelaxIters[0] = 1; + m_levelInterpType[0] = MGRInterpolationType::blockJacobi; + m_levelRestrictType[0] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[0] = MGRCoarseGridMethod::galerkin; + m_levelGlobalSmootherType[0] = MGRGlobalSmootherType::none; + + m_levelFRelaxType[1] = MGRFRelaxationType::jacobi; + m_levelFRelaxIters[1] = 1; + m_levelInterpType[1] = MGRInterpolationType::jacobi; // Diagonal scaling (Jacobi) + m_levelRestrictType[1] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; // Standard Galerkin + m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::blockGaussSeidel; + m_levelGlobalSmootherIters[1] = 1; + + m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; + m_levelFRelaxIters[2] = 1; + m_levelInterpType[2] = MGRInterpolationType::injection; // Injection + m_levelRestrictType[2] = MGRRestrictionType::injection; + m_levelCoarseGridMethod[2] = MGRCoarseGridMethod::cprLikeBlockDiag; // Non-Galerkin Quasi-IMPES CPR + m_levelGlobalSmootherType[2] = MGRGlobalSmootherType::ilu0; + m_levelGlobalSmootherIters[2] = 1; + } + + /** + * @brief Setup the MGR strategy. + * @param precond preconditioner wrapper + * @param mgrData auxiliary MGR data + */ + void setup( LinearSolverParameters::MGR const &, + HyprePrecWrapper & precond, + HypreMGRData & mgrData ) + { + setReduction( precond, mgrData ); + + // Configure the BoomerAMG solver used as mgr coarse solver for the pressure/temperature reduced system + setPressureTemperatureAMG( mgrData.coarseSolver ); + } +}; + +} // namespace mgr + +} // namespace hypre + +} // namespace geos + +#endif /*GEOS_LINEARALGEBRA_INTERFACES_HYPREMGRCOMPOSITIONALMULTIPHASERESERVOIRFVM_HPP_*/ diff --git a/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp b/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp index 46c6280262d..5f1e05394a4 100644 --- a/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp +++ b/src/coreComponents/linearAlgebra/utilities/LinearSolverParameters.hpp @@ -277,6 +277,7 @@ struct LinearSolverParameters compositionalMultiphaseReservoirHybridFVM, ///< hybrid finite volume compositional multiphase flow with wells reactiveCompositionalMultiphaseOBL, ///< finite volume reactive compositional flow with OBL thermalCompositionalMultiphaseFVM, ///< finite volume thermal compositional multiphase flow + thermalCompositionalMultiphaseReservoirFVM,///< finite volume thermal compositional multiphase flow multiphasePoromechanics, ///< multiphase poromechanics with finite volume compositional multiphase flow multiphasePoromechanicsReservoirFVM, ///< multiphase poromechanics with finite volume compositional multiphase flow with wells thermalMultiphasePoromechanics, ///< thermal multiphase poromechanics with finite volume compositional multiphase flow @@ -368,6 +369,7 @@ ENUM_STRINGS( LinearSolverParameters::MGR::StrategyType, "compositionalMultiphaseReservoirHybridFVM", "reactiveCompositionalMultiphaseOBL", "thermalCompositionalMultiphaseFVM", + "thermalCompositionalMultiphaseReservoirFVM", "multiphasePoromechanics", "multiphasePoromechanicsReservoirFVM", "thermalMultiphasePoromechanics", diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 88a7e422a29..9d7f055e16c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -72,7 +72,6 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, m_targetPhaseIndex( -1 ) { - this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useMass ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). @@ -943,10 +942,14 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); arrayView1d< real64 const > const & temp = subRegion.getField< fields::well::temperature >(); + arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >(); - + arrayView2d< real64 const, compflow::USD_COMP > const & pvFrac = subRegion.getField< fields::well::phaseVolumeFraction >(); + arrayView2d< real64 const, compflow::USD_COMP > const & compDens = subRegion.getField< fields::well::globalCompDensity >(); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + + constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { using FluidType = TYPEOFREF( castedFluid ); @@ -960,6 +963,11 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe temp, compFrac ); } ); + std::cout << subRegion.getName(); + for( integer i=0; i const & localMatrix, arrayView1d< real64 > const & localRhs ) { - string const wellDofKey = dofManager.getKey( wellElementDofName()); + // computePerforationRates( domain ); + //return; if( 1 ) { @@ -1029,12 +1038,13 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, [&]( localIndex const, WellElementSubRegion & subRegion ) { - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); int numPhases = fluid.numFluidPhases(); int numComponents = fluid.numFluidComponents(); WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time+ dt ) ) + { if( isThermal() ) { @@ -1066,28 +1076,59 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, localMatrix, localRhs ); } + } + else + { + //wellControls.setWellOpen(false); + // get the degrees of freedom and ghosting info + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); + localIndex rank_offset = dofManager.rankOffset(); + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( wellElemGhostRank[ei] < 0 ) + { + globalIndex const dofIndex = wellElemDofNumber[ei]; + localIndex const localRow = dofIndex - rank_offset; + + real64 unity = 1.0; + for( integer i=0; i < m_numDofPerWellElement; i++ ) + { + globalIndex const rindex = localRow+i; + globalIndex const cindex =dofIndex + i; + localMatrix.template addToRow< serialAtomic >( rindex, + &cindex, + &unity, + 1 ); + localRhs[cindex] = 0.0; + } + } + }); + } } ); } ); + } else { // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); + assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); // then assemble the volume balance equations - assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + assembleVolumeBalanceTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } // then assemble the pressure relations between well elements assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( domain ); + computePerforationRates( time, dt, domain ); // then assemble the flux terms in the mass balance equations // get a reference to the degree-of-freedom numbers if( 0 ) { // then assemble the flux terms in the mass balance equations - assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } else { @@ -1099,11 +1140,12 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, [&]( localIndex const, WellElementSubRegion & subRegion ) { - WellControls const & well_controls = getWellControls( subRegion ); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); int numComponents = fluid.numFluidComponents(); - + WellControls const & well_controls = getWellControls( subRegion ); + if( well_controls.isWellOpen( time+ dt ) ) + { if( isThermal() ) { thermalCompositionalMultiphaseWellKernels:: @@ -1133,6 +1175,7 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, localMatrix, localRhs ); } + } } ); } ); } @@ -1157,7 +1200,7 @@ void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & s updateBHPForConstraint( subRegion ); } -void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain ) +void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) { GEOS_MARK_FUNCTION; @@ -1182,6 +1225,11 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain ) WellElementSubRegion & subRegion ) { WellControls const & wellControls = getWellControls( subRegion ); + + if( time_n <= 0.0 || + ( !wellControls.isWellOpen( time_n ) && wellControls.isWellOpen( time_n + dt ) ) ) + { + PerforationData const & perforationData = *subRegion.getPerforationData(); // get well primary variables on well elements @@ -1266,12 +1314,14 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain ) wellElemPhaseDens, wellElemTotalDens, connRate ); + } } ); } ); } -void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, +void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time, + real64 const & dt, DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, @@ -1294,6 +1344,7 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, { WellControls const & wellControls = getWellControls( subRegion ); + // get a reference to the degree-of-freedom numbers string const wellDofKey = dofManager.getKey( wellElementDofName() ); arrayView1d< globalIndex const > const & wellElemDofNumber = @@ -1337,6 +1388,8 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, WellElementSubRegion & subRegion ) { WellControls const & well_controls = getWellControls( subRegion ); + if( well_controls.isWellOpen( time+ dt ) ) + { string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); int numComponents = fluid.numFluidComponents(); @@ -1370,17 +1423,22 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const dt, localMatrix, localRhs ); } + } } ); } ); } } -void CompositionalMultiphaseWell::assembleAccumulationTerms( DomainPartition const & domain, +void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time, + real64 const & dt, + DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; + GEOS_UNUSED_VAR(time); + GEOS_UNUSED_VAR(dt); string const wellDofKey = dofManager.getKey( wellElementDofName() ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -1450,13 +1508,16 @@ DofManager const & dofManager, } -void CompositionalMultiphaseWell::assembleVolumeBalanceTerms( DomainPartition const & domain, +void CompositionalMultiphaseWell::assembleVolumeBalanceTerms( real64 const & time, + real64 const & dt, + DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR(time); + GEOS_UNUSED_VAR(dt); string const wellDofKey = dofManager.getKey( wellElementDofName() ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -1994,7 +2055,7 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, return MpiWrapper::min( localCheck ); } -void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & domain ) +void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n, real64 const & dt, DomainPartition & domain ) { GEOS_MARK_FUNCTION; @@ -2012,12 +2073,16 @@ void CompositionalMultiphaseWell::computePerforationRates( DomainPartition & dom { WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time_n+ dt ) ) + { + bool const disableReservoirToWellFlow = wellControls.isInjector() and !wellControls.isCrossflowEnabled(); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); bool isThermal = fluid.isThermal(); + PerforationData * const perforationData = subRegion.getPerforationData(); if( 1 ) { @@ -2142,7 +2207,7 @@ if( 1 ) dCompPerfRate_dPres, dCompPerfRate_dComp ); } - + } } ); } ); @@ -2158,6 +2223,7 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager, DomainPartition & domain ) { + DofManager::CompMask pressureMask( m_numDofPerWellElement, 0, 1 ); DofManager::CompMask componentMask( m_numDofPerWellElement, 1, numFluidComponents()+1 ); DofManager::CompMask connRateMask( m_numDofPerWellElement, numFluidComponents()+1, numFluidComponents()+2 ); @@ -2228,6 +2294,8 @@ if( isThermal() ) domain.getNeighbors(), true ); } ); + + } void CompositionalMultiphaseWell::chopNegativeDensities( DomainPartition & domain ) @@ -2340,7 +2408,8 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time WellControls & wellControls = getWellControls( subRegion ); - + if( wellControls.isWellOpen( time_n+ dt ) ) + { string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); bool isThermal = fluid.isThermal(); @@ -2419,6 +2488,7 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() << " from rate constraint to BHP constraint" ); } + } } } ); } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index c91326c7911..65e28fcfb68 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -184,7 +184,8 @@ class CompositionalMultiphaseWell : public WellSolverBase * @brief Recompute the perforation rates for all the wells * @param domain the domain containing the mesh and fields */ - virtual void computePerforationRates( DomainPartition & domain ) override; + virtual void computePerforationRates( real64 const & time_n, + real64 const & dt, DomainPartition & domain ) override; /** * @brief Recompute all dependent quantities from primary variables (including constitutive models) @@ -215,12 +216,13 @@ virtual void assembleSystem( real64 const time, * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleFluxTerms( real64 const dt, + + virtual void assembleFluxTerms( real64 const & time_n, + real64 const & dt, DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; - + arrayView1d< real64 > const & localRhs )override; /** * @brief assembles the accumulation term for all the well elements * @param domain the physical domain object @@ -228,7 +230,9 @@ virtual void assembleSystem( real64 const time, * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleAccumulationTerms( DomainPartition const & domain, + virtual void assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; @@ -240,7 +244,9 @@ virtual void assembleSystem( real64 const time, * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleVolumeBalanceTerms( DomainPartition const & domain, + virtual void assembleVolumeBalanceTerms( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; @@ -389,7 +395,7 @@ virtual void assembleSystem( real64 const time, * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells */ - void initializeWells( DomainPartition & domain ) override; + void initializeWells( DomainPartition & domain , real64 const & time_n, real64 const & dt ) override; virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index b83c72873e0..65d396affb9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -192,6 +192,7 @@ ControlEquationHelper:: if( currentControl == WellControls::Control::BHP ) { // control equation is a difference between current BHP and target BHP + std::cout << "Current control - BHP " << targetBHP << " " << currentBHP << std::endl; controlEqn = currentBHP - targetBHP; dControlEqn_dPres = dCurrentBHP_dPres; dControlEqn[COFFSET_WJ::dP] = dCurrentBHP[Deriv::dP]; @@ -224,6 +225,9 @@ ControlEquationHelper:: // Total volumetric rate control else if( currentControl == WellControls::Control::TOTALVOLRATE ) { + if( targetTotalRate == 0.0 ) + std::cout << "Shutin " << std::endl; + std::cout << "Current control - TOTALVOLRATE " << targetTotalRate << " " << currentTotalVolRate << std::endl; controlEqn = currentTotalVolRate - targetTotalRate; dControlEqn_dPres = dCurrentTotalVolRate_dPres; dControlEqn[COFFSET_WJ::dP] = dCurrentTotalVolRate[COFFSET_WJ::dP]; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 518e75885fc..b2c0b03cc6c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -1830,6 +1830,7 @@ class FaceBasedAssemblyKernel stack.localFluxJacobian[i], CP_Deriv::nDer ); RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], stack.localFlux[i] ); + } } } @@ -2301,7 +2302,6 @@ class FaceBasedAssemblyKernelFactory if( useTotalMassEquation ) kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); - using kernelType = FaceBasedAssemblyKernel< NUM_COMP, 0 >; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index ccc0047828e..dfc9e919998 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -255,6 +255,8 @@ struct StackVariables // b) get well variables pres[TAG::WELL] = m_wellElemPres[iwelem]; + std::cout << "wrpres " << iwelem << " RES " << pres[TAG::RES] << " WELL " << pres[TAG::WELL] + << " dp " << pres[TAG::WELL]-pres[TAG::RES]; dPres_dP[TAG::WELL] = 1.0; dPres[TAG::WELL][CP_Deriv::dP] = 1.0; multiplier[TAG::WELL] = -1.0; @@ -295,7 +297,10 @@ struct StackVariables dPotDiff[i][ic] += multiplier[i] * m_perfTrans[iperf] * dPres[i][ic]; } } - + std::cout << " WELLC " << pres[TAG::WELL] << " dp " << pres[TAG::WELL]-pres[TAG::RES] << + " " << m_wellElemCompDens[iwelem][0] << " " << m_wellElemCompDens[iwelem][1] << " " + << m_wellElemCompFrac[iwelem][0] << " " << m_wellElemCompFrac[iwelem][1]; + std::cout << " potdiff " << potDiff << std::endl; // Step 4: upwinding based on the flow direction @@ -692,7 +697,7 @@ bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; + pflux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dP]; stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dT] - + flux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dT]; + + pflux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dT]; //energy e real64 dPVF_dC[numComp]{}; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 1168eba01df..1d8f2c495b5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -394,7 +394,7 @@ void SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) // note: the perforation rates are updated separately } -void SinglePhaseWell::initializeWells( DomainPartition & domain ) +void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) { GEOS_MARK_FUNCTION; @@ -410,6 +410,9 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain ) WellElementSubRegion & subRegion ) { WellControls const & wellControls = getWellControls( subRegion ); + if( time_n <= 0.0 || ( !wellControls.isWellOpen( time_n ) && wellControls.isWellOpen( time_n + dt ) ) ) + { + PerforationData const & perforationData = *subRegion.getPerforationData(); // get the info stored on well elements @@ -471,14 +474,16 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain ) 0.0, // initialization done at t = 0 wellElemDens, connRate ); + } } ); } ); } -void SinglePhaseWell::assembleFluxTerms( real64 const dt, - DomainPartition & domain, +void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -498,6 +503,10 @@ void SinglePhaseWell::assembleFluxTerms( real64 const dt, [&]( localIndex const, WellElementSubRegion const & subRegion ) { + WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time_n + dt ) ) + { + // get a reference to the degree-of-freedom numbers string const wellDofKey = dofManager.getKey( wellElementDofName() ); arrayView1d< globalIndex const > const & wellElemDofNumber = @@ -517,6 +526,7 @@ void SinglePhaseWell::assembleFluxTerms( real64 const dt, dt, localMatrix, localRhs ); + } } ); } ); @@ -544,7 +554,10 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, WellElementSubRegion const & subRegion ) { + WellControls & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time_n + dt ) ) + { // get the degrees of freedom numbers, depth, next well elem index string const wellDofKey = dofManager.getKey( wellElementDofName() ); @@ -601,12 +614,13 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, << " from rate constraint to BHP constraint" ); } } - + } } ); } ); } -void SinglePhaseWell::assembleAccumulationTerms( DomainPartition const & domain, +void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -677,6 +691,11 @@ if( 1 ) arrayView1d< globalIndex const > const wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellElemDofKey ); arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank(); + WellControls & wellControls = getWellControls( subRegion ); + + if( wellControls.isWellOpen( time_n + dt ) ) + { + arrayView1d< real64 const > const wellElemVolume = subRegion.getElementVolume(); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); @@ -695,13 +714,43 @@ if( 1 ) wellElemDensity_n, localMatrix, localRhs ); + } + else + { + localIndex rank_offset = dofManager.rankOffset(); + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( wellElemGhostRank[ei] < 0 ) + { + + globalIndex const dofIndex = wellElemDofNumber[ei]; + localIndex const localRow = dofIndex - rank_offset; + + + real64 unity = 1.0; + for( integer i=0; i < m_numDofPerWellElement; i++ ) + { + globalIndex const rindex = wellElemDofNumber[ei] + i; + globalIndex const cindex = localRow+1; + localMatrix.template addToRow< serialAtomic >( rindex, + &cindex, + &unity, + 1 ); + localRhs[cindex] = 0.0; + } + } + } ); + + } } ); } ); } } -void SinglePhaseWell::assembleVolumeBalanceTerms( DomainPartition const & GEOS_UNUSED_PARAM( domain ), + void SinglePhaseWell::assembleVolumeBalanceTerms( real64 const & GEOS_UNUSED_PARAM( time_n ), + real64 const & GEOS_UNUSED_PARAM( dt ), + DomainPartition const & GEOS_UNUSED_PARAM( domain ), DofManager const & GEOS_UNUSED_PARAM( dofManager ), CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) @@ -786,7 +835,8 @@ void SinglePhaseWell::shutDownWell( real64 const time_n, } -void SinglePhaseWell::computePerforationRates( DomainPartition & domain ) + void SinglePhaseWell::computePerforationRates( real64 const & time_n, + real64 const & dt, DomainPartition & domain ) { GEOS_MARK_FUNCTION; @@ -804,6 +854,10 @@ void SinglePhaseWell::computePerforationRates( DomainPartition & domain ) WellElementSubRegion & subRegion ) { + WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time_n + dt ) ) + { + // get the well data PerforationData * const perforationData = subRegion.getPerforationData(); @@ -863,6 +917,7 @@ void SinglePhaseWell::computePerforationRates( DomainPartition & domain ) resElementIndex, perfRate, dPerfRate_dPres ); + } } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 3e818eebb05..fdb03ce6673 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -159,7 +159,8 @@ class SinglePhaseWell : public WellSolverBase * @brief Recompute the perforation rates for all the wells * @param domain the domain containing the mesh and fields */ - virtual void computePerforationRates( DomainPartition & domain ) override; + virtual void computePerforationRates( real64 const & time_n, + real64 const & dt, DomainPartition & domain ) override; /** * @brief Recompute all dependent quantities from primary variables (including constitutive models) on the well @@ -176,8 +177,9 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - void assembleFluxTerms( real64 const dt, - DomainPartition & domain, + void assembleFluxTerms( real64 const & time_n, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; @@ -189,7 +191,8 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - void assembleAccumulationTerms( DomainPartition const & domain, + void assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; @@ -201,7 +204,8 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleVolumeBalanceTerms( DomainPartition const & domain, + virtual void assembleVolumeBalanceTerms( real64 const & time_n, + real64 const & dt, DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; @@ -269,7 +273,7 @@ static constexpr char const * dCurrentVolRateString() { return "dCurrentVolumetr * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells */ - void initializeWells( DomainPartition & domain ) override; + void initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) override; /** * @brief Make sure that the well constraints are compatible diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 6b7aef1b453..5bb7aa04167 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -558,7 +558,7 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El // Step 1: assemble the phase-dependent part of the accumulation term of the energy equation real64 const phaseEnergy = phaseAmount * phaseInternalEnergy[ip]; - real64 const phaseEnergy_n = phaseAmount_n * phaseInternalEnergy_n[ip]; + real64 const phaseEnergy_n = phaseAmount_n * phaseInternalEnergy_n[ip]; real64 const dPhaseEnergy_dP = dPhaseAmount[FLUID_PROP_COFFSET::dP] * phaseInternalEnergy[ip] + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP]; real64 const dPhaseEnergy_dT = dPhaseAmount[FLUID_PROP_COFFSET::dT] * phaseInternalEnergy[ip] diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp index ea1232cb7e4..3c7be63183f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp @@ -149,6 +149,7 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs real64 const dFluidEnergy_dP = stack.volume * stack.dDensity_dPres * m_internalEnergy[iwelem][0] + stack.volume * stack.density * m_dInternalEnergy_dPres[iwelem][0]; + real64 const dFluidEnergy_dT = stack.volume * m_dWellElemDensity_dTemperature[iwelem][0] * m_internalEnergy[iwelem][0] + stack.volume * stack.density * m_dInternalEnergy_dTemp[iwelem][0]; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp index 4d97682591b..0089c95c099 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp @@ -172,12 +172,14 @@ void WellControls::switchToBHPControl( real64 const & val ) { m_currentControl = Control::BHP; m_targetBHP = val; + std::cout << "Control BHP " << val << std::endl; } void WellControls::switchToTotalRateControl( real64 const & val ) { m_currentControl = Control::TOTALVOLRATE; m_targetTotalRate = val; + std::cout << "Control TOTALVOLRATE " << val << std::endl; } void WellControls::switchToPhaseRateControl( real64 const & val ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 6cca7f72dd6..090174dadc0 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -51,7 +51,6 @@ m_numPhases( 0 ), setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Flag indicating whether the problem is thermal or not." ); - } Group *WellSolverBase::createChild( string const & childKey, string const & childName ) @@ -167,16 +166,76 @@ void WellSolverBase::setupDofs( DomainPartition const & domain, } void WellSolverBase::implicitStepSetup( real64 const & time_n, - real64 const & GEOS_UNUSED_PARAM( dt ), + real64 const & dt, DomainPartition & domain ) { // Initialize the primary and secondary variables for the first time step - if( time_n <= 0.0 ) + + initializeWells( domain, time_n, dt ); +} + + +void WellSolverBase::shutInWell( real64 const time_n, + real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); + + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) { - initializeWells( domain ); - } + + ElementRegionManager const & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion const & subRegion ) + { + + globalIndex const rankOffset = dofManager.rankOffset(); + + arrayView1d< integer const > const ghostRank = + subRegion.getReference< array1d< integer > >( ObjectManagerBase::viewKeyStruct::ghostRankString() ); + arrayView1d< globalIndex const > const dofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( ghostRank[ei] >= 0 ) + { + return; + } + + globalIndex const dofIndex = dofNumber[ei]; + localIndex const localRow = dofIndex - rankOffset; + + + real64 unity = 1.0; + for( integer i=0; i < m_numDofPerWellElement; i++ ) + { + globalIndex const cindex = dofNumber[ei] + i; + globalIndex const rindex = localRow+i; + localMatrix.template addToRow< serialAtomic >( rindex, + &cindex, + &unity, + 1 ); + localRhs[cindex] = 0.0; + } + + } ); + } ); + } ); } + void WellSolverBase::assembleSystem( real64 const time, real64 const dt, DomainPartition & domain, @@ -260,10 +319,10 @@ void WellSolverBase::assembleSystem( real64 const time, assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( domain ); + computePerforationRates( time, dt, domain ); // then assemble the flux terms in the mass balance equations - assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } else if( 0 ) @@ -326,23 +385,23 @@ void WellSolverBase::assembleSystem( real64 const time, else { // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); + assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); // then assemble the volume balance equations - assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + assembleVolumeBalanceTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } // then assemble the pressure relations between well elements assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( domain ); + computePerforationRates( time, dt, domain ); // then assemble the flux terms in the mass balance equations // get a reference to the degree-of-freedom numbers if( 0 ) { // then assemble the flux terms in the mass balance equations - assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } else { @@ -377,23 +436,23 @@ void WellSolverBase::assembleSystem( real64 const time, else { // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( domain, dofManager, localMatrix, localRhs ); + assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); // then assemble the volume balance equations - assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); + assembleVolumeBalanceTerms( time, dt, domain, dofManager, localMatrix, localRhs ); // then assemble the pressure relations between well elements assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( domain ); + computePerforationRates( time, dt, domain ); // then assemble the flux terms in the mass balance equations - assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); } // then apply a special treatment to the wells that are shut - shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); + //shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); } void WellSolverBase::updateState( DomainPartition & domain ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 3f8c3ba2c43..ec764bae387 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -196,7 +196,8 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleFluxTerms( real64 const dt, + virtual void assembleFluxTerms( real64 const & time_n, + real64 const & dt, DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, @@ -209,7 +210,9 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleAccumulationTerms( DomainPartition const & domain, + virtual void assembleAccumulationTerms( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; @@ -221,7 +224,9 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleVolumeBalanceTerms( DomainPartition const & domain, + virtual void assembleVolumeBalanceTerms( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; @@ -242,6 +247,23 @@ class WellSolverBase : public SolverBase CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; + + /** + * @brief apply a special treatment to the wells that are shut (set Aww=I , Awr=Arw=0) + * @param time_n the time at the previous converged time step + * @param dt the time step size + * @param domain the physical domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param matrix the system matrix + * @param rhs the system right-hand side vector + */ + void shutInWell( real64 const time_n, + real64 const dt, + DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + /** * @brief apply a special treatment to the wells that are shut * @param time_n the time at the previous converged time step @@ -274,7 +296,9 @@ class WellSolverBase : public SolverBase * @brief Recompute the perforation rates for all the wells * @param domain the domain containing the mesh and fields */ - virtual void computePerforationRates( DomainPartition & domain ) = 0; + virtual void computePerforationRates( real64 const & time_n, + real64 const & dt, + DomainPartition & domain ) = 0; struct viewKeyStruct : SolverBase::viewKeyStruct { @@ -304,7 +328,7 @@ static constexpr char const * isThermalString() { return "isThermal"; } * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells */ - virtual void initializeWells( DomainPartition & domain ) = 0; + virtual void initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) = 0; virtual void printRates( real64 const & time_n, real64 const & dt, diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index 5fa587e4515..ad596b156fb 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -104,13 +104,18 @@ void CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase >:: setMGRStrategy() { - if( flowSolver()->getLinearSolverParameters().mgr.strategy == LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseFVM ) + if( flowSolver()->getLinearSolverParameters().mgr.strategy == LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseHybridFVM ) { m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirFVM; + } + else if( isThermal() ) + { + m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::thermalCompositionalMultiphaseReservoirFVM; + } else { - m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirHybridFVM; + m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirFVM; } } @@ -470,6 +475,7 @@ areWellsShut = 0; coupledReservoirAndWellKernels:: ThermalCompositionalMultiPhaseFluxKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( numComps, + wellControls.isProducer(), dt, rankOffset, wellDofKey, diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 3fc0ef3a5c2..816a280c0c1 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -244,7 +244,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); } } - compFluxKernelOp( resOffset, wellElemOffset, dofColIndices ); + compFluxKernelOp( resOffset, wellElemOffset, dofColIndices, iwelem ); } @@ -413,6 +413,7 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM * @param[in] kernelFlags flags packed together */ ThermalCompositionalMultiPhaseFluxKernel( real64 const dt, + integer const isProducer, globalIndex const rankOffset, string const wellDofKey, WellElementSubRegion const & subRegion, @@ -436,6 +437,7 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM detectCrossflow, numCrossFlowPerforations, kernelFlags ), + m_isProducer( isProducer ), m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) @@ -456,8 +458,14 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM { Base::computeFlux( iperf, [&] ( globalIndex const & resOffset, globalIndex const & wellElemOffset, - stackArray1d< globalIndex, 2*resNumDOF > & dofColIndices ) + stackArray1d< globalIndex, 2*resNumDOF > & dofColIndices, + localIndex const iwelem ) + { + // No energy equation if top element and Injector + if( iwelem ==0 && !m_isProducer ) { + return; + } // local working variables and arrays stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 ); @@ -531,6 +539,9 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM protected: + /// Well type + integer const m_isProducer; + /// Views on energy flux arrayView1d< real64 const > const m_energyPerfFlux; arrayView3d< real64 const > const m_dEnergyPerfFlux; @@ -559,6 +570,7 @@ class ThermalCompositionalMultiPhaseFluxKernelFactory template< typename POLICY > static void createAndLaunch( integer const numComps, + integer const isProducer, real64 const dt, globalIndex const rankOffset, string const wellDofKey, @@ -586,7 +598,7 @@ class ThermalCompositionalMultiPhaseFluxKernelFactory using kernelType = ThermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 1 >; - kernelType kernel( dt, rankOffset, wellDofKey, subRegion, resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); + kernelType kernel( dt, isProducer, rankOffset, wellDofKey, subRegion, resDofNumber, perforationData, fluid, localRhs, localMatrix, detectCrossflow, numCrossFlowPerforations, kernelFlags ); kernelType::template launch< POLICY >( perforationData->size(), kernel ); } ); From b4983b014dac2d4c1e45b2eaffb3a82fc145e585 Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Tue, 28 May 2024 09:47:19 -0700 Subject: [PATCH 19/71] merge with dev --- .gitmodules | 3 --- scripts/uberenv | 1 - src/coreComponents/LvArray | 2 +- src/coreComponents/fileIO/coupling/hdf5_interface | 2 +- .../fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp | 4 ++-- .../fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp | 7 +++++++ .../physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp | 2 +- .../schema/docs/CompositionalMultiphaseWell.rst | 2 ++ src/coreComponents/schema/docs/SinglePhaseWell.rst | 1 + src/coreComponents/schema/schema.xsd | 6 ++++++ .../wellsTests/testReservoirSinglePhaseMSWells.cpp | 6 +++--- 11 files changed, 24 insertions(+), 12 deletions(-) delete mode 160000 scripts/uberenv diff --git a/.gitmodules b/.gitmodules index 029ba71a9ab..5552178f5ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,6 +10,3 @@ [submodule "src/coreComponents/fileIO/coupling/hdf5_interface"] path = src/coreComponents/fileIO/coupling/hdf5_interface url = ../../GEOS-DEV/hdf5_interface.git -[submodule "scripts/uberenv"] - path = scripts/uberenv - url = ../../LLNL/uberenv.git diff --git a/scripts/uberenv b/scripts/uberenv deleted file mode 160000 index d0cf52c5894..00000000000 --- a/scripts/uberenv +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0cf52c58949eeb5226e7dbee8b6ac4cbea48b0c diff --git a/src/coreComponents/LvArray b/src/coreComponents/LvArray index 1531241583e..e6b7f90c1aa 160000 --- a/src/coreComponents/LvArray +++ b/src/coreComponents/LvArray @@ -1 +1 @@ -Subproject commit 1531241583eebe21cfcdc0facd16a80f1e03c939 +Subproject commit e6b7f90c1aaa53992962ce6510dc000cc06c1943 diff --git a/src/coreComponents/fileIO/coupling/hdf5_interface b/src/coreComponents/fileIO/coupling/hdf5_interface index 7ee534586a6..5136554439e 160000 --- a/src/coreComponents/fileIO/coupling/hdf5_interface +++ b/src/coreComponents/fileIO/coupling/hdf5_interface @@ -1 +1 @@ -Subproject commit 7ee534586a6ea995532eb4e3cfc7da4e5ccff64a +Subproject commit 5136554439e791dc5e948f2a74ede31c4c697ef5 diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index 4f379def946..765db50bc7e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -225,7 +225,7 @@ ControlEquationHelper:: // Total volumetric rate control else if( currentControl == WellControls::Control::TOTALVOLRATE ) { - if( targetTotalRate == 0.0 ) + if( targetTotalRate <= 0.0 ) std::cout << "Shutin " << std::endl; std::cout << "Current control - TOTALVOLRATE " << targetTotalRate << " " << currentTotalVolRate << std::endl; controlEqn = currentTotalVolRate - targetTotalRate; @@ -1127,7 +1127,7 @@ PerforationKernel:: } for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { - dRelPerm[CP_Deriv::dC+jc]=0; + dRelPerm[jc]=0; } for( integer jp = 0; jp < NP; ++jp ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index b2c0b03cc6c..aea5ccd4bf8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -1977,6 +1977,13 @@ class FaceBasedAssemblyKernel real64 dComp[NC][NC]; real64 dCompFlux[NC][numDof]{}; + for( integer ic = 0; ic < NC; ++ic ) + { + for( integer jc = 0; jc < NC; ++jc ) + { + dComp[ic][jc]=0.0; + } + } // Step 1) decide the upwind well element /* currentConnRate < 0 flow from iwelem to iwelemNext diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 2399aed42d7..1e634bbf1ba 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -627,7 +627,7 @@ void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, { GEOS_MARK_FUNCTION; -if( 1 ) +if( 0 ) { string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst index b072785ff00..6e86f2475ef 100644 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst +++ b/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst @@ -6,10 +6,12 @@ Name Type Default Description allowLocalCompDensityChopping integer 1 Flag indicating whether local (cell-wise) chopping of negative compositions is allowed cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. +isThermal integer 0 Flag indicating whether the problem is thermal or not. logLevel integer 0 Log level maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration maxCompFractionChange real64 1 Maximum (absolute) change in a component fraction between two Newton iterations maxRelativePressureChange real64 1 Maximum (relative) change in pressure between two Newton iterations (recommended with rate control) +maxRelativeTemperatureChange real64 1 Maximum (relative) change in temperature between two Newton iterations name groupName required A name is required for any non-unique nodes targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. useMass integer 0 Use total mass equation diff --git a/src/coreComponents/schema/docs/SinglePhaseWell.rst b/src/coreComponents/schema/docs/SinglePhaseWell.rst index ba2a66c6297..6338cbcd994 100644 --- a/src/coreComponents/schema/docs/SinglePhaseWell.rst +++ b/src/coreComponents/schema/docs/SinglePhaseWell.rst @@ -5,6 +5,7 @@ Name Type Default Description ========================= ================== ======== ====================================================================================================================================================================================================================================================================================================================== cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. +isThermal integer 0 Flag indicating whether the problem is thermal or not. logLevel integer 0 Log level name groupName required A name is required for any non-unique nodes targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd index 00397845810..21a74888912 100644 --- a/src/coreComponents/schema/schema.xsd +++ b/src/coreComponents/schema/schema.xsd @@ -2567,6 +2567,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -2575,6 +2577,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + @@ -3328,6 +3332,8 @@ Local - Add stabilization only to interiors of macro elements.--> + + diff --git a/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp index 2948d71f72c..da4c20aa094 100644 --- a/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp @@ -384,7 +384,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleFluxTerms( DT, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleFluxTerms(TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } @@ -414,7 +414,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleAccumulationTerms( domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleAccumulationTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } @@ -496,7 +496,7 @@ TEST_F( SinglePhaseReservoirSolverInternalWellTest, jacobianNumericalCheck_Flux [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleFluxTerms( DT, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } From d2971119c0cd400ca0caef8b2006b4e2d8900574 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Fri, 31 May 2024 08:27:31 -0700 Subject: [PATCH 20/71] code cleanup --- .../common/KernelLaunchSelectors.hpp | 92 +- .../constitutive/fluid/multifluid/Layouts.hpp | 4 +- .../fluid/singlefluid/SingleFluidBase.hpp | 10 +- ...malCompositionalMultiphaseReservoirFVM.hpp | 2 +- ...rmalCompositionalMultiphaseBaseKernels.hpp | 64 +- .../wells/CompositionalMultiphaseWell.cpp | 1365 ++++++---------- .../wells/CompositionalMultiphaseWell.hpp | 36 +- .../CompositionalMultiphaseWellFields.hpp | 39 - .../CompositionalMultiphaseWellKernels.cpp | 1399 +---------------- .../CompositionalMultiphaseWellKernels.hpp | 488 +----- .../wells/PerforationFluxKernels.hpp | 364 ++--- .../fluidFlow/wells/SinglePhaseWell.cpp | 635 ++++---- .../fluidFlow/wells/SinglePhaseWell.hpp | 26 +- ...rmalCompositionalMultiphaseWellKernels.hpp | 57 +- .../wells/ThermalSinglePhaseWellKernels.hpp | 22 +- .../wells/WellElementKernelUtilities.hpp | 136 +- .../fluidFlow/wells/WellSolverBase.cpp | 223 +-- .../fluidFlow/wells/WellSolverBase.hpp | 28 +- ...mpositionalMultiphaseReservoirAndWells.cpp | 235 +-- .../CoupledReservoirAndWellKernels.hpp | 381 +++-- .../SinglePhaseReservoirAndWells.cpp | 104 +- ...eservoirCompositionalMultiphaseMSWells.cpp | 14 - .../testReservoirSinglePhaseMSWells.cpp | 2 +- 23 files changed, 1510 insertions(+), 4216 deletions(-) diff --git a/src/coreComponents/common/KernelLaunchSelectors.hpp b/src/coreComponents/common/KernelLaunchSelectors.hpp index b8547458218..bc0a9bf2105 100644 --- a/src/coreComponents/common/KernelLaunchSelectors.hpp +++ b/src/coreComponents/common/KernelLaunchSelectors.hpp @@ -100,64 +100,64 @@ void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); if( n_phase == 1 ) { - switch( value ) + switch( value ) + { + case 1: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 1 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 1 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 1 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 1 >() ); return; } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 1 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 1 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } } else if( n_phase == 2 ) { - switch( value ) + switch( value ) + { + case 1: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 2 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 2 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 2 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 2 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 2 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 2 >() ); return; } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 2 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 2 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 2 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 2 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } } else if( n_phase == 3 ) { - switch( value ) + switch( value ) + { + case 1: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 3 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 3 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 3 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 3 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 3 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 3 >() ); return; } + case 2: + { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 3 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 3 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 3 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 3 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } } else { @@ -167,5 +167,5 @@ void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) } // end namspace internal } // end namespace geos - + #endif // GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP diff --git a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp index 6e80a4252d8..4cd75e52da9 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/Layouts.hpp @@ -59,14 +59,14 @@ struct DerivativeOffset /// indices of pressure, temperature, and composition derivatives template< integer NC, integer IS_THERMAL > struct DerivativeOffsetC {}; - + template< integer NC > struct DerivativeOffsetC< NC, 1 > { /// index of derivative wrt pressure static integer constexpr dP = 0; /// index of derivative wrt temperature - static integer constexpr dT = dP + 1; + static integer constexpr dT = dP + 1; /// index of first derivative wrt compositions static integer constexpr dC = dP+2; /// number of derivatives diff --git a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp index b3be95bd5f9..20d46f7dd9b 100644 --- a/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/singlefluid/SingleFluidBase.hpp @@ -276,11 +276,11 @@ class SingleFluidBase : public ConstitutiveBase virtual real64 defaultViscosity() const = 0; /** - * @brief Get the thermal flag. - * @return boolean value indicating whether the model can be used to assemble the energy balance equation or not - * @detail if isThermal is true, the constitutive model compute the enthalpy and internal energy of the phase. - * This can be used to check the compatibility of the constitutive model with the solver - */ + * @brief Get the thermal flag. + * @return boolean value indicating whether the model can be used to assemble the energy balance equation or not + * @detail if isThermal is true, the constitutive model compute the enthalpy and internal energy of the phase. + * This can be used to check the compatibility of the constitutive model with the solver + */ virtual bool isThermal() const { return false; } protected: diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp index 992b3c49ef0..b9433861988 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp @@ -56,7 +56,7 @@ class ThermalCompositionalMultiphaseReservoirFVM : public MGRStrategyBase< 3 > explicit ThermalCompositionalMultiphaseReservoirFVM( arrayView1d< int const > const & numComponentsPerField ) : MGRStrategyBase( LvArray::integerConversion< HYPRE_Int >( numComponentsPerField[0] + numComponentsPerField[1] ) ) { - HYPRE_Int const numResLabels = LvArray::integerConversion< HYPRE_Int >( numComponentsPerField[0] ); + HYPRE_Int const numResLabels = LvArray::integerConversion< HYPRE_Int >( numComponentsPerField[0] ); // Level 0: eliminate the well block m_labels[0].resize( numResLabels ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp index 8e62e14e545..559565cc469 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp @@ -2436,45 +2436,45 @@ void KernelLaunchSelector_NC_NP_THERM( integer const numComp, integer const numP // Ideally this would be inside the dispatch, but it breaks on Summit with GCC 9.1.0 and CUDA 11.0.3. if( isThermal ) { - if( numPhase == 2 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + if( numPhase == 2 ) { - KERNELWRAPPER::template launch< NC(), 2, 1 >( std::forward< ARGS >( args ) ... ); - } ); - } - else if( numPhase == 3 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2, 1 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) { - KERNELWRAPPER::template launch< NC(), 3, 1 >( std::forward< ARGS >( args ) ... ); - } ); - } - else - { - GEOS_ERROR( "Unsupported number of phases: " << numPhase ); - } + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3, 1 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } } else { - if( numPhase == 2 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + if( numPhase == 2 ) { - KERNELWRAPPER::template launch< NC(), 2, 0 >( std::forward< ARGS >( args ) ... ); - } ); - } - else if( numPhase == 3 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2, 0 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) { - KERNELWRAPPER::template launch< NC(), 3, 0 >( std::forward< ARGS >( args ) ... ); - } ); - } - else - { - GEOS_ERROR( "Unsupported number of phases: " << numPhase ); - } + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3, 0 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 78650570b6c..981854c7e75 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -62,7 +62,7 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, Group * const parent ) : WellSolverBase( name, parent ), - m_useMass( false ), + m_useMass( false ), m_useTotalMassEquation( 1 ), m_maxCompFracChange( 1.0 ), m_maxRelativePresChange( 0.2 ), @@ -155,9 +155,9 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) MultiFluidBase const & fluid0 = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName ); m_numPhases = fluid0.numFluidPhases(); m_numComponents = fluid0.numFluidComponents(); - } + } m_numDofPerWellElement = isThermal() ? m_numComponents + 3 : m_numComponents + 2; // 1 pressure + NC compositions + 1 connectionRate + - // temp if thermal + // temp if thermal m_numDofPerResElement = isThermal() ? m_numComponents + 2 : m_numComponents + 1; // 1 pressure + NC compositions + temp if thermal // loop over the wells @@ -210,14 +210,6 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< fields::well::totalMassDensity >( getName() ); subRegion.registerField< fields::well::dTotalMassDensity >( getName() ). reference().resizeDimension< 1 >( m_numComponents +2 ); // dP, dT, dC - // tjb - remove - subRegion.registerField< fields::well::dTotalMassDensity_dPressure >( getName() ); - subRegion.registerField< fields::well::dTotalMassDensity_dGlobalCompDensity >( getName() ). - reference().resizeDimension< 1 >( m_numComponents ); - if( fluid.isThermal() ) - { - subRegion.registerField< fields::well::dTotalMassDensity_dTemperature >( getName() ); - } subRegion.registerField< fields::well::phaseVolumeFraction_n >( getName() ). reference().resizeDimension< 1 >( m_numPhases ); @@ -237,11 +229,6 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) perforationData.registerField< fields::well::dEnergyPerforationFlux >( getName() ). reference().resizeDimension< 1, 2 >( 2, m_numComponents+2 ); } - // tjb - remove - perforationData.registerField< fields::well::dCompPerforationRate_dPres >( getName() ). - reference().resizeDimension< 1, 2 >( 2, m_numComponents ); - perforationData.registerField< fields::well::dCompPerforationRate_dComp >( getName() ). - reference().resizeDimension< 1, 2, 3 >( 2, m_numComponents, m_numComponents ); WellControls & wellControls = getWellControls( subRegion ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() ); @@ -250,14 +237,6 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) setSizedFromParent( 0 ). reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC - //tjb - remove - wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentBHP_dPresString() ). - setRestartFlags( RestartFlags::NO_WRITE ); - //tjb - remove - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHP_dCompDensString() ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numComponents ); wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::currentPhaseVolRateString() ). setSizedFromParent( 0 ). @@ -267,21 +246,6 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) setSizedFromParent( 0 ). reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents + 3 ); // dP, dT, dC, dQ - //tjb -remove - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dPresString() ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numPhases ); - //tjb remove - wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentPhaseVolRate_dRateString() ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numPhases ); - wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() ); @@ -290,14 +254,6 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) reference().resizeDimension< 0 >( m_numComponents + 3 ); // dP, dT, dC dQ wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() ); - wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentTotalVolRate_dPresString() ). - setRestartFlags( RestartFlags::NO_WRITE ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ). - setRestartFlags( RestartFlags::NO_WRITE ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( m_numComponents ); - wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentTotalVolRate_dRateString() ). - setRestartFlags( RestartFlags::NO_WRITE ); // write rates output header // the rank that owns the reference well element is responsible @@ -629,9 +585,6 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & arrayView1d< real64 > const & totalMassDens = subRegion.getField< fields::well::totalMassDensity >(); arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens = subRegion.getField< fields::well::dTotalMassDensity >(); - arrayView1d< real64 > const & dTotalMassDens_dPres = subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); - arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens_dCompDens = subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); - arrayView1d< real64 const > const wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); // control data @@ -646,45 +599,35 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & arrayView1d< real64 > const & dCurrentBHP = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); - real64 & dCurrentBHP_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); - arrayView1d< real64 > const & dCurrentBHP_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dCompDensString() ); - geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) - { - //integer constexpr NUM_COMP = NC(); - integer constexpr IS_THERMAL = ISTHERMAL(); -GEOS_UNUSED_VAR( NC ); - // bring everything back to host, capture the scalars by reference - forAll< serialPolicy >( 1, [&numComp, - pres, - totalMassDens, - dTotalMassDens, - dTotalMassDens_dPres, - dTotalMassDens_dCompDens, - wellElemGravCoef, - ¤tBHP, - &dCurrentBHP, - &dCurrentBHP_dPres, - dCurrentBHP_dCompDens, - &iwelemRef, - &refGravCoef] ( localIndex const ) + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { - real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; - currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef; - dCurrentBHP_dPres = 1 + dTotalMassDens_dPres[iwelemRef] * diffGravCoef; - dCurrentBHP[Deriv::dP] = 1 + dTotalMassDens_dPres[iwelemRef] * diffGravCoef; - for( integer ic = 0; ic < numComp; ++ic ) - { - dCurrentBHP_dCompDens[ic] = dTotalMassDens_dCompDens[iwelemRef][ic] * diffGravCoef; - dCurrentBHP[Deriv::dC+ic] = dTotalMassDens_dCompDens[iwelemRef][ic] * diffGravCoef; - } - if constexpr ( IS_THERMAL ) + //integer constexpr NUM_COMP = NC(); + integer constexpr IS_THERMAL = ISTHERMAL(); + GEOS_UNUSED_VAR( NC ); + // bring everything back to host, capture the scalars by reference + forAll< serialPolicy >( 1, [&numComp, + pres, + totalMassDens, + dTotalMassDens, + wellElemGravCoef, + ¤tBHP, + &dCurrentBHP, + &iwelemRef, + &refGravCoef] ( localIndex const ) { - dCurrentBHP[Deriv::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef; - } - } ); + real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; + currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef; + dCurrentBHP[Deriv::dP] = 1 + dTotalMassDens[iwelemRef][Deriv::dP] * diffGravCoef; + for( integer ic = 0; ic < numComp; ++ic ) + { + dCurrentBHP[Deriv::dC+ic] = dTotalMassDens[iwelemRef][Deriv::dC+ic] * diffGravCoef; + } + if constexpr ( IS_THERMAL ) + { + dCurrentBHP[Deriv::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef; + } } ); + } ); if( logLevel >= 2 ) { @@ -747,193 +690,164 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); arrayView2d< real64 > const & dCurrentPhaseVolRate = wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); - // tjb - remove - arrayView1d< real64 > const & dCurrentPhaseVolRate_dPres = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); - arrayView1d< real64 > const & dCurrentPhaseVolRate_dRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dRateString() ); - arrayView2d< real64 > const & dCurrentPhaseVolRate_dCompDens = - wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ); + real64 & currentTotalVolRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); arrayView1d< real64 > const & dCurrentTotalVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); - // TJB - remove - real64 & dCurrentTotalVolRate_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); - arrayView1d< real64 > const & dCurrentTotalVolRate_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ); - real64 & dCurrentTotalVolRate_dRate = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dRateString() ); + real64 & massDensity = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() ); constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr IS_THERMAL = ISTHERMAL(); - using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NUM_COMP, IS_THERMAL >; - // bring everything back to host, capture the scalars by reference - forAll< serialPolicy >( 1, [&numComp, - &numPhase, - fluidWrapper, - pres, - temp, - compFrac, - dCompFrac_dCompDens, - connRate, - totalDens, - dTotalDens, - phaseDens, - dPhaseDens, - phaseFrac, - dPhaseFrac, - &useSurfaceConditions, - &surfacePres, - &surfaceTemp, - ¤tTotalVolRate, - dCurrentTotalVolRate, - &dCurrentTotalVolRate_dPres, - dCurrentTotalVolRate_dCompDens, - &dCurrentTotalVolRate_dRate, - currentPhaseVolRate, - dCurrentPhaseVolRate, - dCurrentPhaseVolRate_dPres, - dCurrentPhaseVolRate_dCompDens, - dCurrentPhaseVolRate_dRate, - &iwelemRef, - &logLevel, - &wellControlsName, - &massUnit, - &massDensity] ( localIndex const ) + geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { - GEOS_UNUSED_VAR( massUnit ); - using Deriv = multifluid::DerivativeOffset; - stackArray1d< real64, maxNumComp > work( numComp ); - // Step 1: evaluate the phase and total density in the reference element - - // We need to evaluate the density as follows: - // - Surface conditions: using the surface pressure provided by the user - // - Reservoir conditions: using the pressure in the top element - if( useSurfaceConditions ) + integer constexpr NUM_COMP = NC(); + integer constexpr IS_THERMAL = ISTHERMAL(); + using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NUM_COMP, IS_THERMAL >; + // bring everything back to host, capture the scalars by reference + forAll< serialPolicy >( 1, [&numComp, + &numPhase, + fluidWrapper, + pres, + temp, + compFrac, + dCompFrac_dCompDens, + connRate, + totalDens, + dTotalDens, + phaseDens, + dPhaseDens, + phaseFrac, + dPhaseFrac, + &useSurfaceConditions, + &surfacePres, + &surfaceTemp, + ¤tTotalVolRate, + dCurrentTotalVolRate, + currentPhaseVolRate, + dCurrentPhaseVolRate, + &iwelemRef, + &logLevel, + &wellControlsName, + &massUnit, + &massDensity] ( localIndex const ) { - // we need to compute the surface density - fluidWrapper.update( iwelemRef, 0, surfacePres, surfaceTemp, compFrac[iwelemRef] ); - if( logLevel >= 2 ) + GEOS_UNUSED_VAR( massUnit ); + using Deriv = multifluid::DerivativeOffset; + stackArray1d< real64, maxNumComp > work( numComp ); + // Step 1: evaluate the phase and total density in the reference element + + // We need to evaluate the density as follows: + // - Surface conditions: using the surface pressure provided by the user + // - Reservoir conditions: using the pressure in the top element + if( useSurfaceConditions ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa and T_surface = {} K", - wellControlsName, surfacePres, surfaceTemp ) ); + // we need to compute the surface density + fluidWrapper.update( iwelemRef, 0, surfacePres, surfaceTemp, compFrac[iwelemRef] ); + if( logLevel >= 2 ) + { + GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa and T_surface = {} K", + wellControlsName, surfacePres, surfaceTemp ) ); #ifdef GEOS_USE_HIP - GEOS_UNUSED_VAR( wellControlsName ); + GEOS_UNUSED_VAR( wellControlsName ); #endif + } } - } - else - { - real64 const refPres = pres[iwelemRef]; - fluidWrapper.update( iwelemRef, 0, refPres, temp[iwelemRef], compFrac[iwelemRef] ); - } - - // Step 2: update the total volume rate - - real64 const currentTotalRate = connRate[iwelemRef]; - - // Step 2.1: compute the inverse of the total density and derivatives - massDensity =totalDens[iwelemRef][0]; // need to verify this is surface dens - real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; - - stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); - for( integer ic = 0; ic < numComp; ++ic ) - { - dTotalDensInv_dCompDens[ic] = -dTotalDens[iwelemRef][0][Deriv::dC+ic] * totalDensInv * totalDensInv; - } - applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dTotalDensInv_dCompDens, work.data() ); - - // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate - currentTotalVolRate = currentTotalRate * totalDensInv; - // Compute derivatives dP dT - real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; - dCurrentTotalVolRate_dPres = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; - dCurrentTotalVolRate[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; - if constexpr ( IS_THERMAL ) - { - dCurrentTotalVolRate[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv; - } - - dCurrentTotalVolRate_dRate = totalDensInv; - dCurrentTotalVolRate[COFFSET_WJ::dQ] = dCurrentTotalVolRate_dRate; - for( integer ic = 0; ic < numComp; ++ic ) - { - dCurrentTotalVolRate_dCompDens[ic] = currentTotalRate * dTotalDensInv_dCompDens[ic]; - dCurrentTotalVolRate[COFFSET_WJ::dC+ic] = currentTotalRate * dTotalDensInv_dCompDens[ic]; - } - - if( logLevel >= 2 && useSurfaceConditions ) - { - GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} {}/sm3. \n" - "The total rate is {} {}/s, which corresponds to a total surface volumetric rate of {} sm3/s", - wellControlsName, totalDens[iwelemRef][0], massUnit, - currentTotalRate, massUnit, currentTotalVolRate ) ); - } - - // Step 3: update the phase volume rate - for( integer ip = 0; ip < numPhase; ++ip ) - { - - // Step 3.1: compute the inverse of the (phase density * phase fraction) and derivatives - - // skip the rest of this function if phase ip is absent - bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0); - if( !phaseExists ) + else { - continue; + real64 const refPres = pres[iwelemRef]; + fluidWrapper.update( iwelemRef, 0, refPres, temp[iwelemRef], compFrac[iwelemRef] ); } - real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip]; - real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv; - real64 const dPhaseFracTimesPhaseDensInv_dPres = dPhaseFrac[iwelemRef][0][ip][Deriv::dP] * phaseDensInv - - dPhaseDens[iwelemRef][0][ip][Deriv::dP] * phaseFracTimesPhaseDensInv * phaseDensInv; + // Step 2: update the total volume rate + real64 const currentTotalRate = connRate[iwelemRef]; + + // Step 2.1: compute the inverse of the total density and derivatives + massDensity =totalDens[iwelemRef][0]; // need to verify this is surface dens + real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; - // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate - currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv; - dCurrentPhaseVolRate[ip][COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; - dCurrentPhaseVolRate_dPres[ip] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; - dCurrentPhaseVolRate_dRate[ip] = phaseFracTimesPhaseDensInv; - dCurrentPhaseVolRate[ip][COFFSET_WJ::dQ] = phaseFracTimesPhaseDensInv; - if constexpr (IS_THERMAL ) + stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); + for( integer ic = 0; ic < numComp; ++ic ) { - real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv - - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv; - dCurrentPhaseVolRate[ip][COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp; + dTotalDensInv_dCompDens[ic] = -dTotalDens[iwelemRef][0][Deriv::dC+ic] * totalDensInv * totalDensInv; } - for( integer ic = 0; ic < numComp; ++ic ) + applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dTotalDensInv_dCompDens, work.data() ); + + // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate + currentTotalVolRate = currentTotalRate * totalDensInv; + // Compute derivatives dP dT + real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv; + dCurrentTotalVolRate[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres; + if constexpr ( IS_THERMAL ) { - dCurrentPhaseVolRate_dCompDens[ip][ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; - dCurrentPhaseVolRate_dCompDens[ip][ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; - dCurrentPhaseVolRate_dCompDens[ip][ic] *= currentTotalRate; + dCurrentTotalVolRate[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv; } - applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dCurrentPhaseVolRate_dCompDens[ip], work.data() ); + + dCurrentTotalVolRate[COFFSET_WJ::dQ] = totalDensInv; for( integer ic = 0; ic < numComp; ++ic ) { - dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; - dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; - dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] *= currentTotalRate; + dCurrentTotalVolRate[COFFSET_WJ::dC+ic] = currentTotalRate * dTotalDensInv_dCompDens[ic]; } - applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], &dCurrentPhaseVolRate[ip][COFFSET_WJ::dC], work.data() ); if( logLevel >= 2 && useSurfaceConditions ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: The density of phase {} at surface conditions is {} {}/sm3. \n" - "The phase surface volumetric rate is {} sm3/s", - wellControlsName, ip, phaseDens[iwelemRef][0][ip], massUnit, currentPhaseVolRate[ip] ) ); + GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} {}/sm3. \n" + "The total rate is {} {}/s, which corresponds to a total surface volumetric rate of {} sm3/s", + wellControlsName, totalDens[iwelemRef][0], massUnit, + currentTotalRate, massUnit, currentTotalVolRate ) ); } - } + + // Step 3: update the phase volume rate + for( integer ip = 0; ip < numPhase; ++ip ) + { + + // Step 3.1: compute the inverse of the (phase density * phase fraction) and derivatives + + // skip the rest of this function if phase ip is absent + bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0); + if( !phaseExists ) + { + continue; + } + + real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip]; + real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv; + real64 const dPhaseFracTimesPhaseDensInv_dPres = dPhaseFrac[iwelemRef][0][ip][Deriv::dP] * phaseDensInv + - dPhaseDens[iwelemRef][0][ip][Deriv::dP] * phaseFracTimesPhaseDensInv * phaseDensInv; + + + // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate + currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dQ] = phaseFracTimesPhaseDensInv; + if constexpr (IS_THERMAL ) + { + real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv + - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp; + } + + for( integer ic = 0; ic < numComp; ++ic ) + { + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv; + dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] *= currentTotalRate; + } + applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], &dCurrentPhaseVolRate[ip][COFFSET_WJ::dC], work.data() ); + + if( logLevel >= 2 && useSurfaceConditions ) + { + GEOS_LOG_RANK( GEOS_FMT( "{}: The density of phase {} at surface conditions is {} {}/sm3. \n" + "The phase surface volumetric rate is {} sm3/s", + wellControlsName, ip, phaseDens[iwelemRef][0][ip], massUnit, currentPhaseVolRate[ip] ) ); + } + } + } ); } ); } ); - } ); } @@ -1019,106 +933,18 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & } void CompositionalMultiphaseWell::assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { string const wellDofKey = dofManager.getKey( wellElementDofName()); - // computePerforationRates( domain ); - //return; - if( 1 ) - { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - int numPhases = fluid.numFluidPhases(); - int numComponents = fluid.numFluidComponents(); - WellControls const & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time+ dt ) ) - { - if( isThermal() ) - { + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - thermalCompositionalMultiphaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - numPhases, - wellControls.isProducer(), - dofManager.rankOffset(), - m_useTotalMassEquation, - wellDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - } - else - { - compositionalMultiphaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - numPhases, - wellControls.isProducer(), - dofManager.rankOffset(), - m_useTotalMassEquation, - wellDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - } - } - else - { - //wellControls.setWellOpen(false); - // get the degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); - localIndex rank_offset = dofManager.rankOffset(); - forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( wellElemGhostRank[ei] < 0 ) - { - globalIndex const dofIndex = wellElemDofNumber[ei]; - localIndex const localRow = dofIndex - rank_offset; - real64 unity = 1.0; - for( integer i=0; i < m_numDofPerWellElement; i++ ) - { - globalIndex const rindex = localRow+i; - globalIndex const cindex =dofIndex + i; - localMatrix.template addToRow< serialAtomic >( rindex, - &cindex, - &unity, - 1 ); - localRhs[cindex] = 0.0; - } - } - }); - } - } ); - } ); - - } - else - { - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then assemble the volume balance equations - assembleVolumeBalanceTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - } // then assemble the pressure relations between well elements assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); // then compute the perforation rates (later assembled by the coupled solver) @@ -1145,37 +971,37 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); int numComponents = fluid.numFluidComponents(); WellControls const & well_controls = getWellControls( subRegion ); - if( well_controls.isWellOpen( time+ dt ) ) - { - if( isThermal() ) - { - thermalCompositionalMultiphaseWellKernels:: - FaceBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - dt, - dofManager.rankOffset(), - m_useTotalMassEquation, - wellDofKey, - well_controls, - subRegion, - fluid, - localMatrix, - localRhs ); - } - else + if( well_controls.isWellOpen( time+ dt ) ) { - compositionalMultiphaseWellKernels:: - FaceBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - dt, - dofManager.rankOffset(), - m_useTotalMassEquation, - wellDofKey, - well_controls, - subRegion, - localMatrix, - localRhs ); - } + if( isThermal() ) + { + thermalCompositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + FaceBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + dt, + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + well_controls, + subRegion, + localMatrix, + localRhs ); + } } } ); } ); @@ -1231,90 +1057,90 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea ( !wellControls.isWellOpen( time_n ) && wellControls.isWellOpen( time_n + dt ) ) ) { - PerforationData const & perforationData = *subRegion.getPerforationData(); - - // get well primary variables on well elements - arrayView1d< real64 > const & wellElemPressure = subRegion.getField< fields::well::pressure >(); - arrayView1d< real64 > const & wellElemTemp = subRegion.getField< fields::well::temperature >(); - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); - - // get the info stored on well elements - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< fields::well::globalCompFraction >(); - arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = perforationData.getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = perforationData.getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = perforationData.getField< fields::perforation::reservoirElementIndex >(); - - arrayView1d< real64 const > const & perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >(); - - // 1) Loop over all perforations to compute an average mixture density and component fraction - // 2) Initialize the reference pressure - // 3) Estimate the pressures in the well elements using the average density - PresTempCompFracInitializationKernel:: - launch( perforationData.size(), - subRegion.size(), - numComp, - numPhase, - perforationData.getNumPerforationsGlobal(), - wellControls, - 0.0, // initialization done at t = 0 - resCompFlowAccessors.get( fields::flow::pressure{} ), - resCompFlowAccessors.get( fields::flow::temperature{} ), - resCompFlowAccessors.get( fields::flow::globalCompDensity{} ), - resCompFlowAccessors.get( fields::flow::phaseVolumeFraction{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseMassDensity{} ), - resElementRegion, - resElementSubRegion, - resElementIndex, - perfGravCoef, - wellElemGravCoef, - wellElemPressure, - wellElemTemp, - wellElemCompFrac ); - - // get well secondary variables on well elements - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); - arrayView2d< real64 const, multifluid::USD_FLUID > const & wellElemTotalDens = fluid.totalDensity(); - - // 4) Back calculate component densities - constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) - { - typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - - thermalCompositionalMultiphaseBaseKernels:: - FluidUpdateKernel:: - launch< serialPolicy >( subRegion.size(), - fluidWrapper, - wellElemPressure, - wellElemTemp, - wellElemCompFrac ); - } ); - - CompDensInitializationKernel::launch( subRegion.size(), - numComp, - wellElemCompFrac, - wellElemTotalDens, - wellElemCompDens ); - - // 5) Recompute the pressure-dependent properties - updateSubRegionState( subRegion ); - - // 6) Estimate the well rates - // TODO: initialize rates using perforation rates - compositionalMultiphaseWellKernels:: - RateInitializationKernel:: - launch( subRegion.size(), - m_targetPhaseIndex, - wellControls, - 0.0, // initialization done at t = 0 - wellElemPhaseDens, - wellElemTotalDens, - connRate ); + PerforationData const & perforationData = *subRegion.getPerforationData(); + + // get well primary variables on well elements + arrayView1d< real64 > const & wellElemPressure = subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 > const & wellElemTemp = subRegion.getField< fields::well::temperature >(); + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); + + // get the info stored on well elements + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< fields::well::globalCompFraction >(); + arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); + + // get the element region, subregion, index + arrayView1d< localIndex const > const resElementRegion = perforationData.getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const resElementSubRegion = perforationData.getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const resElementIndex = perforationData.getField< fields::perforation::reservoirElementIndex >(); + + arrayView1d< real64 const > const & perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >(); + + // 1) Loop over all perforations to compute an average mixture density and component fraction + // 2) Initialize the reference pressure + // 3) Estimate the pressures in the well elements using the average density + PresTempCompFracInitializationKernel:: + launch( perforationData.size(), + subRegion.size(), + numComp, + numPhase, + perforationData.getNumPerforationsGlobal(), + wellControls, + 0.0, // initialization done at t = 0 + resCompFlowAccessors.get( fields::flow::pressure{} ), + resCompFlowAccessors.get( fields::flow::temperature{} ), + resCompFlowAccessors.get( fields::flow::globalCompDensity{} ), + resCompFlowAccessors.get( fields::flow::phaseVolumeFraction{} ), + resMultiFluidAccessors.get( fields::multifluid::phaseMassDensity{} ), + resElementRegion, + resElementSubRegion, + resElementIndex, + perfGravCoef, + wellElemGravCoef, + wellElemPressure, + wellElemTemp, + wellElemCompFrac ); + + // get well secondary variables on well elements + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); + arrayView2d< real64 const, multifluid::USD_FLUID > const & wellElemTotalDens = fluid.totalDensity(); + + // 4) Back calculate component densities + constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid ) + { + typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); + + thermalCompositionalMultiphaseBaseKernels:: + FluidUpdateKernel:: + launch< serialPolicy >( subRegion.size(), + fluidWrapper, + wellElemPressure, + wellElemTemp, + wellElemCompFrac ); + } ); + + CompDensInitializationKernel::launch( subRegion.size(), + numComp, + wellElemCompFrac, + wellElemTotalDens, + wellElemCompDens ); + + // 5) Recompute the pressure-dependent properties + updateSubRegionState( subRegion ); + + // 6) Estimate the well rates + // TODO: initialize rates using perforation rates + compositionalMultiphaseWellKernels:: + RateInitializationKernel:: + launch( subRegion.size(), + m_targetPhaseIndex, + wellControls, + 0.0, // initialization done at t = 0 + wellElemPhaseDens, + wellElemTotalDens, + connRate ); } } ); @@ -1330,66 +1156,18 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time, { GEOS_MARK_FUNCTION; - if( 0 ) - { - // loop over the wells - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - WellControls const & wellControls = getWellControls( subRegion ); - - - // get a reference to the degree-of-freedom numbers - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); - // get a reference to the primary variables on well elements - arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); - - // get the info stored on well elements - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< fields::well::globalCompFraction >(); - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< FluxKernel >( numFluidComponents(), - subRegion.size(), - dofManager.rankOffset(), - m_useTotalMassEquation, - wellControls, - wellElemDofNumber, - nextWellElemIndex, - connRate, - wellElemCompFrac, - dWellElemCompFrac_dCompDens, - dt, - localMatrix, - localRhs ); - } ); - } ); - } - else + string const wellDofKey = dofManager.getKey( wellElementDofName()); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - string const wellDofKey = dofManager.getKey( wellElementDofName()); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - WellControls const & well_controls = getWellControls( subRegion ); - if( well_controls.isWellOpen( time+ dt ) ) + WellControls const & well_controls = getWellControls( subRegion ); + if( well_controls.isWellOpen( time+ dt ) ) { string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); @@ -1424,141 +1202,103 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time, localMatrix, localRhs ); } - } - } ); + } } ); - } + } ); + } void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time, real64 const & dt, - DomainPartition const & domain, -DofManager const & dofManager, + DomainPartition & domain, + DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - GEOS_UNUSED_VAR(time); - GEOS_UNUSED_VAR(dt); + GEOS_UNUSED_VAR( time ); + GEOS_UNUSED_VAR( dt ); string const wellDofKey = dofManager.getKey( wellElementDofName() ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) { + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + int numPhases = fluid.numFluidPhases(); + int numComponents = fluid.numFluidComponents(); + WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time+ dt ) ) + { + if( isThermal() ) + { - // get the degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); - - // get the properties on the well element - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac = - subRegion.getField< fields::well::phaseVolumeFraction >(); - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac = - subRegion.getField< fields::well::dPhaseVolumeFraction >(); - - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = - subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); - - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n = - subRegion.getField< fields::well::phaseVolumeFraction_n >(); - - arrayView1d< real64 const > const & wellElemVolume = subRegion.getElementVolume(); + thermalCompositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + wellControls.isProducer(), + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + else + { + compositionalMultiphaseWellKernels:: + ElementBasedAssemblyKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComponents, + numPhases, + wellControls.isProducer(), + dofManager.rankOffset(), + m_useTotalMassEquation, + wellDofKey, + subRegion, + fluid, + localMatrix, + localRhs ); + } + } + else + { + //wellControls.setWellOpen(false); + // get the degrees of freedom and ghosting info + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); + localIndex rank_offset = dofManager.rankOffset(); + forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( wellElemGhostRank[ei] < 0 ) + { + globalIndex const dofIndex = wellElemDofNumber[ei]; + localIndex const localRow = dofIndex - rank_offset; - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity(); - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens = fluid.dPhaseDensity(); - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac = fluid.phaseCompFraction(); - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac = fluid.dPhaseCompFraction(); - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n = fluid.phaseDensity_n(); - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n = fluid.phaseCompFraction_n(); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< AccumulationKernel >( numFluidComponents(), - subRegion.size(), - numFluidPhases(), - dofManager.rankOffset(), - m_useTotalMassEquation, - wellElemDofNumber, - wellElemGhostRank, - wellElemVolume, - wellElemPhaseVolFrac, - dWellElemPhaseVolFrac, - dWellElemCompFrac_dCompDens, - wellElemPhaseDens, - dWellElemPhaseDens, - wellElemPhaseCompFrac, - dWellElemPhaseCompFrac, - wellElemPhaseVolFrac_n, - wellElemPhaseDens_n, - wellElemPhaseCompFrac_n, - localMatrix, - localRhs ); + real64 unity = 1.0; + for( integer i=0; i < m_numDofPerWellElement; i++ ) + { + globalIndex const rindex = localRow+i; + globalIndex const cindex =dofIndex + i; + localMatrix.template addToRow< serialAtomic >( rindex, + &cindex, + &unity, + 1 ); + localRhs[cindex] = 0.0; + } + } + } ); + } } ); } ); -} - - -void CompositionalMultiphaseWell::assembleVolumeBalanceTerms( real64 const & time, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - GEOS_MARK_FUNCTION; - GEOS_UNUSED_VAR(time); - GEOS_UNUSED_VAR(dt); - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - // get the degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank(); - // get the properties on the well element - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac = - subRegion.getField< fields::well::phaseVolumeFraction >(); - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac = - subRegion.getField< fields::well::dPhaseVolumeFraction >(); - - arrayView1d< real64 const > const & wellElemVolume = - subRegion.getReference< array1d< real64 > >( ElementSubRegionBase::viewKeyStruct::elementVolumeString() ); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector1< VolumeBalanceKernel >( numFluidComponents(), - subRegion.size(), - numFluidPhases(), - dofManager.rankOffset(), - wellElemDofNumber, - wellElemGhostRank, - wellElemPhaseVolFrac, - dWellElemPhaseVolFrac, - wellElemVolume, - localMatrix, - localRhs ); - } ); - } ); } @@ -1566,12 +1306,12 @@ real64 CompositionalMultiphaseWell::calculateResidualNorm1( real64 const & time_n, real64 const & dt, DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ) + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) { GEOS_MARK_FUNCTION; -integer numNorm = 1; // mass balance + integer numNorm = 1; // mass balance array1d< real64 > localResidualNorm; array1d< real64 > localResidualNormalizer; @@ -1598,7 +1338,7 @@ integer numNorm = 1; // mass balance [&]( localIndex const, WellElementSubRegion const & subRegion ) { - + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); @@ -1698,7 +1438,7 @@ CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, { return calculateResidualNorm1( time_n, dt, domain, dofManager, localRhs ); - + GEOS_MARK_FUNCTION; real64 localResidualNorm = 0.0; @@ -1774,33 +1514,33 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, real64 scalingFactor = 1.0; if( 0 ) { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - // check that pressure and component densities are non-negative - auto const subRegionData = - compositionalMultiphaseWellKernels:: - ScalingForSystemSolutionKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, - m_maxAbsolutePresChange, - m_maxCompFracChange, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution ); + mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) + { + // check that pressure and component densities are non-negative + auto const subRegionData = + compositionalMultiphaseWellKernels:: + ScalingForSystemSolutionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, + m_maxAbsolutePresChange, + m_maxCompFracChange, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution ); - scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); - } ); + scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); + } ); - } ); + } ); - return LvArray::math::max( MpiWrapper::min( scalingFactor ), m_minScalingFactor ); + return LvArray::math::max( MpiWrapper::min( scalingFactor ), m_minScalingFactor ); } else { @@ -1915,14 +1655,14 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, if( 0 ) { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); arrayView2d< real64 const, compflow::USD_COMP > const compDens = @@ -1930,31 +1670,31 @@ CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain, arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); - auto const subRegionData = - compositionalMultiphaseWellKernels:: - SolutionCheckKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, - CompositionalMultiphaseFVM::ScalingType::Global, - scalingFactor, + auto const subRegionData = + compositionalMultiphaseWellKernels:: + SolutionCheckKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping, + CompositionalMultiphaseFVM::ScalingType::Global, + scalingFactor, pressure, compDens, pressureScalingFactor, compDensScalingFactor, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution ); + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution ); - if( !subRegionData.localMinVal ) - { - GEOS_LOG_LEVEL( 1, "Solution is invalid in well " << subRegion.getName() - << " (either a negative pressure or a negative component density was found)." ); - } + if( !subRegionData.localMinVal ) + { + GEOS_LOG_LEVEL( 1, "Solution is invalid in well " << subRegion.getName() + << " (either a negative pressure or a negative component density was found)." ); + } - localCheck = std::min( localCheck, subRegionData.localMinVal ); + localCheck = std::min( localCheck, subRegionData.localMinVal ); + } ); } ); - } ); } else { @@ -2061,8 +1801,8 @@ void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n GEOS_MARK_FUNCTION; forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { // TODO: change the way we access the flowSolver here @@ -2070,23 +1810,22 @@ void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) + WellElementSubRegion & subRegion ) { WellControls const & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time_n+ dt ) ) + if( wellControls.isWellOpen( time_n+ dt ) ) { - bool const disableReservoirToWellFlow = wellControls.isInjector() and !wellControls.isCrossflowEnabled(); + bool const disableReservoirToWellFlow = wellControls.isInjector() and !wellControls.isCrossflowEnabled(); - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - bool isThermal = fluid.isThermal(); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + bool isThermal = fluid.isThermal(); - PerforationData * const perforationData = subRegion.getPerforationData(); -if( 1 ) - { + PerforationData * const perforationData = subRegion.getPerforationData(); + if( isThermal ) { thermalPerforationFluxKernels:: @@ -2112,103 +1851,8 @@ if( 1 ) elemManager, disableReservoirToWellFlow ); } - } - else - { - PerforationKernel::CompFlowAccessors resCompFlowAccessors( elemManager, flowSolver.getName() ); - PerforationKernel::MultiFluidAccessors resMultiFluidAccessors( elemManager, flowSolver.getName() ); - PerforationKernel::RelPermAccessors resRelPermAccessors( elemManager, flowSolver.getName() ); - - // get depth - arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >(); - - // get well primary variables on well elements - arrayView1d< real64 const > const & wellElemPres = - subRegion.getField< fields::well::pressure >(); - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens = - subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 const > const & wellElemTotalMassDens = - subRegion.getField< fields::well::totalMassDensity >(); - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens = - subRegion.getField< fields::well::dTotalMassDensity >(); - //tjb - remove - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres = - subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = - subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); - - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac = - subRegion.getField< fields::well::globalCompFraction >(); - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens = - subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >(); - - // get well variables on perforations - arrayView1d< real64 const > const & perfGravCoef = - perforationData->getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - arrayView1d< real64 const > const perfTrans = - perforationData->getField< fields::perforation::wellTransmissibility >(); - - arrayView2d< real64 > const & compPerfRate = - perforationData->getField< fields::well::compPerforationRate >(); - arrayView4d< real64 > const & dCompPerfRate = - perforationData->getField< fields::well::dCompPerforationRate >(); - // tjb - remove - arrayView3d< real64 > const & dCompPerfRate_dPres = - perforationData->getField< fields::well::dCompPerforationRate_dPres >(); - arrayView4d< real64 > const & dCompPerfRate_dComp = - perforationData->getField< fields::well::dCompPerforationRate_dComp >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelector_NC_NP_THERM< PerforationKernel >( numFluidComponents(), - numFluidPhases(), - isThermal, - perforationData->size(), - disableReservoirToWellFlow, - resCompFlowAccessors.get( fields::flow::pressure{} ), - resCompFlowAccessors.get( fields::flow::phaseVolumeFraction{} ), - resCompFlowAccessors.get( fields::flow::dPhaseVolumeFraction{} ), - resCompFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseDensity{} ), - resMultiFluidAccessors.get( fields::multifluid::dPhaseDensity{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseViscosity{} ), - resMultiFluidAccessors.get( fields::multifluid::dPhaseViscosity{} ), - resMultiFluidAccessors.get( fields::multifluid::phaseCompFraction{} ), - resMultiFluidAccessors.get( fields::multifluid::dPhaseCompFraction{} ), - resRelPermAccessors.get( fields::relperm::phaseRelPerm{} ), - resRelPermAccessors.get( fields::relperm::dPhaseRelPerm_dPhaseVolFraction{} ), - wellElemGravCoef, - wellElemPres, - wellElemCompDens, - wellElemTotalMassDens, - dWellElemTotalMassDens, - dWellElemTotalMassDens_dPres, - dWellElemTotalMassDens_dCompDens, - wellElemCompFrac, - dWellElemCompFrac_dCompDens, - perfGravCoef, - perfWellElemIndex, - perfTrans, - resElementRegion, - resElementSubRegion, - resElementIndex, - compPerfRate, - dCompPerfRate, - dCompPerfRate_dPres, - dCompPerfRate_dComp ); -} - } } ); } ); @@ -2251,7 +1895,7 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager, connRateMask ); //{ m_numDofPerWellElement, m_numDofPerWellElement - 1, m_numDofPerWellElement } ); -if( isThermal() ) + if( isThermal() ) { DofManager::CompMask temperatureMask( m_numDofPerWellElement, numFluidComponents()+2, numFluidComponents()+3 ); @@ -2277,18 +1921,18 @@ if( isThermal() ) FieldIdentifiers fieldsToBeSync; if( isThermal() ) { - fieldsToBeSync.addElementFields( { fields::well::pressure::key(), - fields::well::globalCompDensity::key(), + fieldsToBeSync.addElementFields( { fields::well::pressure::key(), + fields::well::globalCompDensity::key(), fields::well::mixtureConnectionRate::key(), fields::well::temperature::key() }, - regionNames ); -} + regionNames ); + } else - { - fieldsToBeSync.addElementFields( { fields::well::pressure::key(), - fields::well::globalCompDensity::key(), - fields::well::mixtureConnectionRate::key() }, - regionNames ); + { + fieldsToBeSync.addElementFields( { fields::well::pressure::key(), + fields::well::globalCompDensity::key(), + fields::well::mixtureConnectionRate::key() }, + regionNames ); } CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync, mesh, @@ -2367,7 +2011,7 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & subRegion.getField< fields::well::temperature >(); arrayView1d< real64 const > const & wellElemTemperature_n = subRegion.getField< fields::well::temperature_n >(); - wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n ); + wellElemTemperature.setValues< parallelDevicePolicy<> >( wellElemTemperature_n ); } arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity = subRegion.getField< fields::well::globalCompDensity >(); @@ -2411,85 +2055,80 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time if( wellControls.isWellOpen( time_n+ dt ) ) { - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - bool isThermal = fluid.isThermal(); - // get the degrees of freedom, depth info, next welem index - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< real64 const > const & wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); - - // get primary variables on well elements - arrayView1d< real64 const > const & wellElemPres = - subRegion.getField< fields::well::pressure >(); - - // get total mass density on well elements (for potential calculations) - arrayView1d< real64 const > const & wellElemTotalMassDens = - subRegion.getField< fields::well::totalMassDensity >(); - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens = - subRegion.getField< fields::well::dTotalMassDensity >(); - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres = - subRegion.getField< fields::well::dTotalMassDensity_dPressure >(); - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens = - subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >(); - bool controlHasSwitched = false; - isothermalCompositionalMultiphaseBaseKernels:: - KernelLaunchSelectorCompTherm< PressureRelationKernel >( numFluidComponents(), isThermal, - //isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1< - // PressureRelationKernel >( numFluidComponents(), - subRegion.size(), - dofManager.rankOffset(), - subRegion.isLocallyOwned(), - subRegion.getTopWellElementIndex(), - isThermal, - m_targetPhaseIndex, - wellControls, - time_n + dt, // controls evaluated with BHP/rate of the end of step - wellElemDofNumber, - wellElemGravCoef, - nextWellElemIndex, - wellElemPres, - wellElemTotalMassDens, - dWellElemTotalMassDens, - dWellElemTotalMassDens_dPres, - dWellElemTotalMassDens_dCompDens, - controlHasSwitched, - localMatrix, - localRhs ); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); + bool isThermal = fluid.isThermal(); + // get the degrees of freedom, depth info, next welem index + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< real64 const > const & wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); + arrayView1d< localIndex const > const & nextWellElemIndex = + subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); + + // get primary variables on well elements + arrayView1d< real64 const > const & wellElemPres = + subRegion.getField< fields::well::pressure >(); - if( controlHasSwitched ) - { - // TODO: move the switch logic into wellControls - // TODO: implement a more general switch when more then two constraints per well type are allowed + // get total mass density on well elements (for potential calculations) + arrayView1d< real64 const > const & wellElemTotalMassDens = + subRegion.getField< fields::well::totalMassDensity >(); + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens = + subRegion.getField< fields::well::dTotalMassDensity >(); + + bool controlHasSwitched = false; + isothermalCompositionalMultiphaseBaseKernels:: + KernelLaunchSelectorCompTherm< PressureRelationKernel >( numFluidComponents(), isThermal, + //isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1< + // PressureRelationKernel >( numFluidComponents(), + subRegion.size(), + dofManager.rankOffset(), + subRegion.isLocallyOwned(), + subRegion.getTopWellElementIndex(), + isThermal, + m_targetPhaseIndex, + wellControls, + time_n + dt, // controls evaluated with BHP/rate of the end of step + wellElemDofNumber, + wellElemGravCoef, + nextWellElemIndex, + wellElemPres, + wellElemTotalMassDens, + dWellElemTotalMassDens, + controlHasSwitched, + localMatrix, + localRhs ); + + if( controlHasSwitched ) + { + // TODO: move the switch logic into wellControls + // TODO: implement a more general switch when more then two constraints per well type are allowed - real64 const timeAtEndOfStep = time_n + dt; + real64 const timeAtEndOfStep = time_n + dt; - if( wellControls.getControl() == WellControls::Control::BHP ) - { - if( wellControls.isProducer() ) + if( wellControls.getControl() == WellControls::Control::BHP ) { - wellControls.switchToPhaseRateControl( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from BHP constraint to phase volumetric rate constraint" ); + if( wellControls.isProducer() ) + { + wellControls.switchToPhaseRateControl( wellControls.getTargetPhaseRate( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() + << " from BHP constraint to phase volumetric rate constraint" ); + } + else + { + wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() + << " from BHP constraint to total volumetric rate constraint" ); + } } else { - wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); + wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from BHP constraint to total volumetric rate constraint" ); + << " from rate constraint to BHP constraint" ); } } - else - { - wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from rate constraint to BHP constraint" ); - } - } } } ); } ); @@ -2621,7 +2260,7 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, { arrayView1d< real64 > const & wellElemTemperature_n = - subRegion.getField< fields::well::temperature_n >(); + subRegion.getField< fields::well::temperature_n >(); wellElemTemperature_n.setValues< parallelDevicePolicy<> >( wellElemTemperature ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 096d96b3054..b94acb95852 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -201,12 +201,12 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual localIndex numFluidPhases() const override { return m_numPhases; } -virtual void assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; + virtual void assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the flux terms for all connections between well elements * @param time_n previous time value @@ -232,25 +232,11 @@ virtual void assembleSystem( real64 const time, */ virtual void assembleAccumulationTerms( real64 const & time_n, real64 const & dt, - DomainPartition const & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - /** - * @brief assembles the volume balance terms for all well elements - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void assembleVolumeBalanceTerms( real64 const & time_n, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; - /** * @brief assembles the pressure relations at all connections between well elements except at the well head * @param time_n time at the beginning of the time step @@ -395,12 +381,12 @@ virtual void assembleSystem( real64 const time, * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells */ - void initializeWells( DomainPartition & domain , real64 const & time_n, real64 const & dt ) override; + void initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) override; virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override; - - + + /// flag indicating whether mass or molar formulation should be used integer m_useMass; @@ -431,7 +417,7 @@ virtual void assembleSystem( real64 const time, /// index of the target phase, used to impose the phase rate constraint localIndex m_targetPhaseIndex; - + }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp index 6e1bae9b22e..70fe95e959d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp @@ -145,31 +145,6 @@ DECLARE_FIELD( dTotalMassDensity, NO_WRITE, "Derivative of total mass density with respect to pressure, temperature, and global component density" ); -//tjb - remove -DECLARE_FIELD( dTotalMassDensity_dPressure, - "dTotalMassDensity_dPressure", - array1d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of total mass density with respect to pressure" ); -//tjb - remove -DECLARE_FIELD( dTotalMassDensity_dTemperature, - "dTotalMassDensity_dTemperature", - array1d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of total mass density with respect to temperature" ); - -//tjb - remove -DECLARE_FIELD( dTotalMassDensity_dGlobalCompDensity, - "dTotalMassDensity_dComp", // to avoid a rebaseline - array2dLayoutFluid_dC, - 0, - NOPLOT, - NO_WRITE, - "Derivative of total mass density with respect to global component density" ); DECLARE_FIELD( compPerforationRate, "compPerforationRate", @@ -187,21 +162,7 @@ DECLARE_FIELD( dCompPerforationRate, NO_WRITE, "Derivative of component perforation rate with respect to pressure temperature and global component density" ); -DECLARE_FIELD( dCompPerforationRate_dPres, - "dCompPerforationRate_dPres", - array3d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of component perforation rate with respect to pressure" ); -DECLARE_FIELD( dCompPerforationRate_dComp, - "dCompPerforationRate_dComp", - array4d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of component perforation rate with respect to global component density" ); DECLARE_FIELD( globalCompDensityScalingFactor, "globalCompDensityScalingFactor", diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index 765db50bc7e..a01e4027361 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -133,43 +133,21 @@ ControlEquationHelper:: real64 const & targetMassRate, real64 const & currentBHP, arrayView1d< real64 const > const & dCurrentBHP, - real64 const & dCurrentBHP_dPres, - arrayView1d< real64 const > const & dCurrentBHP_dCompDens, arrayView1d< real64 const > const & currentPhaseVolRate, arrayView2d< real64 const > const & dCurrentPhaseVolRate, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, - arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, + real64 const & currentTotalVolRate, arrayView1d< real64 const > const & dCurrentTotalVolRate, - real64 const & dCurrentTotalVolRate_dPres, - arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, - real64 const & dCurrentTotalVolRate_dRate, real64 const & massDensity, globalIndex const dofNumber, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - //using ROFFSETC = compositionalMultiphaseWellKernels::RowOffsetComplete; using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; using Deriv = multifluid::DerivativeOffset; - //using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - //using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - GEOS_UNUSED_VAR( dCurrentBHP ); - GEOS_UNUSED_VAR( dCurrentPhaseVolRate ); - GEOS_UNUSED_VAR( dCurrentTotalVolRate ); localIndex const eqnRowIndex = dofNumber + ROFFSET::CONTROL - rankOffset; - globalIndex const presDofColIndex = dofNumber + COFFSET::DPRES; - globalIndex const rateDofColIndex = dofNumber + COFFSET::DCOMP + NC; - - globalIndex compDofColIndices[NC]{}; - for( integer ic = 0; ic < NC; ++ic ) - { - compDofColIndices[ ic ] = presDofColIndex + ic + 1; - } - // remove above globalIndex dofColIndices[COFFSET_WJ::nDer]{}; for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic ) { @@ -177,9 +155,6 @@ ControlEquationHelper:: } real64 controlEqn = 0; - real64 dControlEqn_dPres = 0; - real64 dControlEqn_dRate = 0; - real64 dControlEqn_dComp[NC]{}; real64 dControlEqn[NC+2+IS_THERMAL]{}; // Note: We assume in the computation of currentBHP that the reference elevation @@ -194,15 +169,13 @@ ControlEquationHelper:: // control equation is a difference between current BHP and target BHP std::cout << "Current control - BHP " << targetBHP << " " << currentBHP << std::endl; controlEqn = currentBHP - targetBHP; - dControlEqn_dPres = dCurrentBHP_dPres; dControlEqn[COFFSET_WJ::dP] = dCurrentBHP[Deriv::dP]; for( integer ic = 0; ic < NC; ++ic ) { - dControlEqn_dComp[ic] = dCurrentBHP_dCompDens[ic]; dControlEqn[COFFSET_WJ::dC+ic] = dCurrentBHP[Deriv::dC+ic]; } if constexpr ( IS_THERMAL ) - + dControlEqn[COFFSET_WJ::dT] = dCurrentBHP[Deriv::dT]; } @@ -210,13 +183,10 @@ ControlEquationHelper:: else if( currentControl == WellControls::Control::PHASEVOLRATE ) { controlEqn = currentPhaseVolRate[targetPhaseIndex] - targetPhaseRate; - dControlEqn_dPres = dCurrentPhaseVolRate_dPres[targetPhaseIndex]; dControlEqn[COFFSET_WJ::dP] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dP]; - dControlEqn_dRate = dCurrentPhaseVolRate_dRate[targetPhaseIndex]; - dControlEqn[COFFSET_WJ::dQ] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dQ]; + dControlEqn[COFFSET_WJ::dQ] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dQ]; for( integer ic = 0; ic < NC; ++ic ) { - dControlEqn_dComp[ic] = dCurrentPhaseVolRate_dCompDens[targetPhaseIndex][ic]; dControlEqn[COFFSET_WJ::dC+ic] = dCurrentPhaseVolRate[targetPhaseIndex][COFFSET_WJ::dC+ic]; } if constexpr ( IS_THERMAL ) @@ -229,13 +199,10 @@ ControlEquationHelper:: std::cout << "Shutin " << std::endl; std::cout << "Current control - TOTALVOLRATE " << targetTotalRate << " " << currentTotalVolRate << std::endl; controlEqn = currentTotalVolRate - targetTotalRate; - dControlEqn_dPres = dCurrentTotalVolRate_dPres; dControlEqn[COFFSET_WJ::dP] = dCurrentTotalVolRate[COFFSET_WJ::dP]; - dControlEqn_dRate = dCurrentTotalVolRate_dRate; dControlEqn[COFFSET_WJ::dQ] = dCurrentTotalVolRate[COFFSET_WJ::dQ]; for( integer ic = 0; ic < NC; ++ic ) { - dControlEqn_dComp[ic] = dCurrentTotalVolRate_dCompDens[ic]; dControlEqn[COFFSET_WJ::dC+ic] = dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; } if constexpr ( IS_THERMAL ) @@ -245,13 +212,10 @@ ControlEquationHelper:: else if( currentControl == WellControls::Control::MASSRATE ) { controlEqn = massDensity*currentTotalVolRate - targetMassRate; - dControlEqn_dPres = massDensity*dCurrentTotalVolRate_dPres; dControlEqn[COFFSET_WJ::dP] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dP]; - dControlEqn_dRate = massDensity*dCurrentTotalVolRate_dRate; dControlEqn[COFFSET_WJ::dQ] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dQ]; for( integer ic = 0; ic < NC; ++ic ) { - dControlEqn_dComp[ic] = massDensity*dCurrentTotalVolRate_dCompDens[ic]; dControlEqn[COFFSET_WJ::dC+ic] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; } if constexpr ( IS_THERMAL ) @@ -261,11 +225,11 @@ ControlEquationHelper:: else if( currentControl == WellControls::Control::MASSRATE ) { controlEqn = massDensity*currentTotalVolRate - targetMassRate; - dControlEqn_dPres = massDensity*dCurrentTotalVolRate_dPres; - dControlEqn_dRate = massDensity*dCurrentTotalVolRate_dRate; + dControlEqn[COFFSET_WJ::dP] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dP]; + dControlEqn[COFFSET_WJ::dQ] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dQ]; for( integer ic = 0; ic < NC; ++ic ) { - dControlEqn_dComp[ic] = massDensity*dCurrentTotalVolRate_dCompDens[ic]; + dControlEqn[COFFSET_WJ::dC+ic] = massDensity*dCurrentTotalVolRate[COFFSET_WJ::dC+ic]; } } else @@ -273,361 +237,15 @@ ControlEquationHelper:: GEOS_ERROR( "This constraint is not supported in CompositionalMultiphaseWell" ); } localRhs[eqnRowIndex] += controlEqn; - if( 0 ) - { - localMatrix.addToRow< serialAtomic >( eqnRowIndex, - &presDofColIndex, - &dControlEqn_dPres, - 1 ); - localMatrix.addToRow< serialAtomic >( eqnRowIndex, - &rateDofColIndex, - &dControlEqn_dRate, - 1 ); - localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex, - compDofColIndices, - dControlEqn_dComp, - NC ); - } - else - { - localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex, - dofColIndices, - dControlEqn, - COFFSET_WJ::nDer ); - } - // tjb- remove when safe and modify local matrix updates - assert( fabs( dControlEqn[COFFSET_WJ::dP] -dControlEqn_dPres ) < FLT_EPSILON ); - assert( fabs( dControlEqn[COFFSET_WJ::dQ] - dControlEqn_dRate ) < FLT_EPSILON ); - for( integer ic=0; ic -GEOS_HOST_DEVICE -void -FluxKernel:: - computeExit( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & oneSidedFlux )[NC], - real64 ( & oneSidedFluxJacobian_dRate )[NC][1], - real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ) -{ - for( integer ic = 0; ic < NC; ++ic ) - { - oneSidedFlux[ic] = -dt * compFlux[ic]; - - // derivative with respect to rate - oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; - - // derivative with respect to upstream pressure - oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; - - // derivatives with respect to upstream component densities - for( integer jdof = 0; jdof < NC; ++jdof ) - { - oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; - } - } -} - -template< integer NC > -GEOS_HOST_DEVICE -void -FluxKernel:: - compute( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( & localFlux )[2*NC], - real64 ( & localFluxJacobian_dRate )[2*NC][1], - real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ) -{ - // flux terms - for( integer ic = 0; ic < NC; ++ic ) - { - localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; - localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; - - // derivative with respect to rate - localFluxJacobian_dRate[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dRate[ic]; - localFluxJacobian_dRate[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dRate[ic]; - - // derivative with respect to upstream pressure - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][0] = dt * dCompFlux_dPresUp[ic]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][0] = -dt * dCompFlux_dPresUp[ic]; - - // derivatives with respect to upstream component densities - for( integer jdof = 0; jdof < NC; ++jdof ) - { - localFluxJacobian_dPresCompUp[TAG::NEXT *NC+ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; - localFluxJacobian_dPresCompUp[TAG::CURRENT *NC+ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; - } - } -} - -template< integer NC > -void -FluxKernel:: - launch( localIndex const size, - globalIndex const rankOffset, - integer const useTotalMassEquation, - WellControls const & wellControls, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< localIndex const > const & nextWellElemIndex, - arrayView1d< real64 const > const & connRate, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - using namespace compositionalMultiphaseUtilities; - - bool const isProducer = wellControls.isProducer(); - arrayView1d< real64 const > const & injection = wellControls.getInjectionStream(); - - // loop over the well elements to compute the fluxes between elements - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - // create local work arrays - real64 compFracUp[NC]{}; - real64 dCompFrac_dCompDensUp[NC][NC]{}; - - real64 compFlux[NC]{}; - real64 dCompFlux_dRate[NC]{}; - real64 dCompFlux_dPresUp[NC]{}; - real64 dCompFlux_dCompDensUp[NC][NC]{}; - - // Step 1) decide the upwind well element - - /* currentConnRate < 0 flow from iwelem to iwelemNext - * currentConnRate > 0 flow from iwelemNext to iwelem - * With this convention, currentConnRate < 0 at the last connection for a producer - * currentConnRate > 0 at the last connection for a injector - */ - - localIndex const iwelemNext = nextWellElemIndex[iwelem]; - real64 const currentConnRate = connRate[iwelem]; - localIndex iwelemUp = -1; - - if( iwelemNext < 0 && !isProducer ) // exit connection, injector - { - // we still need to define iwelemUp for Jacobian assembly - iwelemUp = iwelem; - - // just copy the injection stream into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = injection[ic]; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFrac_dCompDensUp[ic][jc] = 0.0; - } - } - } - else - { - // first set iwelemUp to the upstream cell - if( ( iwelemNext < 0 && isProducer ) // exit connection, producer - || currentConnRate < 0 ) // not an exit connection, iwelem is upstream - { - iwelemUp = iwelem; - } - else // not an exit connection, iwelemNext is upstream - { - iwelemUp = iwelemNext; - } - - // copy the vars of iwelemUp into compFrac - for( integer ic = 0; ic < NC; ++ic ) - { - compFracUp[ic] = wellElemCompFrac[iwelemUp][ic]; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFrac_dCompDensUp[ic][jc] = dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; - } - } - } - - // Step 2) compute upstream transport coefficient - - for( integer ic = 0; ic < NC; ++ic ) - { - compFlux[ic] = compFracUp[ic] * currentConnRate; - dCompFlux_dRate[ic] = compFracUp[ic]; - dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure - for( integer jc = 0; jc < NC; ++jc ) - { - dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; - } - } - - globalIndex const offsetUp = wellElemDofNumber[iwelemUp]; - globalIndex const offsetCurrent = wellElemDofNumber[iwelem]; - - if( iwelemNext < 0 ) // exit connection - { - // for this case, we only need NC mass conservation equations - // so we do not use the arrays initialized before the loop - real64 oneSidedFlux[NC]{}; - real64 oneSidedFluxJacobian_dRate[NC][1]{}; - real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; - - computeExit< NC >( dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - oneSidedFlux, - oneSidedFluxJacobian_dRate, - oneSidedFluxJacobian_dPresCompUp ); - - - globalIndex oneSidedEqnRowIndices[NC]{}; - globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; - globalIndex oneSidedDofColIndices_dRate = 0; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - oneSidedEqnRowIndices[ic] = offsetUp + ROFFSET::MASSBAL + ic - rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - oneSidedDofColIndices_dRate = offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - oneSidedDofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); - } - - for( integer i = 0; i < NC; ++i ) - { - if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < localMatrix.numRows() ) - { - localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - &oneSidedDofColIndices_dRate, - oneSidedFluxJacobian_dRate[i], - 1 ); - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - oneSidedDofColIndices_dPresCompUp, - oneSidedFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); - } - } - } - else // not an exit connection - { - real64 localFlux[2*NC]{}; - real64 localFluxJacobian_dRate[2*NC][1]{}; - real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; - compute< NC >( dt, - compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - localFlux, - localFluxJacobian_dRate, - localFluxJacobian_dPresCompUp ); - - - globalIndex eqnRowIndices[2*NC]{}; - globalIndex dofColIndices_dPresCompUp[NC+1]{}; - globalIndex dofColIndices_dRate = 0; - - globalIndex const offsetNext = wellElemDofNumber[iwelemNext]; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - eqnRowIndices[TAG::NEXT *NC+ic] = offsetNext + ROFFSET::MASSBAL + ic - rankOffset; - eqnRowIndices[TAG::CURRENT *NC+ic] = offsetCurrent + ROFFSET::MASSBAL + ic - rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - dofColIndices_dRate = offsetCurrent + dRateColOffset; + localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex, + dofColIndices, + dControlEqn, + COFFSET_WJ::nDer ); - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - dofColIndices_dPresCompUp[jdof] = offsetUp + COFFSET::DPRES + jdof; - } - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); - } - - for( integer i = 0; i < 2*NC; ++i ) - { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < localMatrix.numRows() ) - { - localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], - &dofColIndices_dRate, - localFluxJacobian_dRate[i], - 1 ); - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices_dPresCompUp, - localFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndices[i]], localFlux[i] ); - } - } - } - } ); } -#define INST_FluxKernel( NC ) \ - template \ - void FluxKernel:: \ - launch< NC >( localIndex const size, \ - globalIndex const rankOffset, \ - integer const useTotalMassEquation, \ - WellControls const & wellControls, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< localIndex const > const & nextWellElemIndex, \ - arrayView1d< real64 const > const & connRate, \ - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, \ - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, \ - real64 const & dt, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_FluxKernel( 1 ); -INST_FluxKernel( 2 ); -INST_FluxKernel( 3 ); -INST_FluxKernel( 4 ); -INST_FluxKernel( 5 ); - /******************************** PressureRelationKernel ********************************/ template< integer NC, integer IS_THERMAL > @@ -642,33 +260,19 @@ PressureRelationKernel:: real64 const & totalMassDensNext, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, - real64 const & dTotalMassDens_dPres, - real64 const & dTotalMassDens_dPresNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, real64 & localPresRel, real64 ( & localPresRelJacobian )[2*(NC+1 + IS_THERMAL)] ) { -GEOS_UNUSED_VAR( dTotalMassDens_dPres ); - - GEOS_UNUSED_VAR( dTotalMassDens_dCompDens ); - GEOS_UNUSED_VAR( dTotalMassDens_dPresNext ); - GEOS_UNUSED_VAR( dTotalMassDens_dCompDensNext ); - // local working variables and arrays real64 dAvgMassDens_dCompCurrent[NC]{}; real64 dAvgMassDens_dCompNext[NC]{}; // compute the average density at the interface between well elements real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); - //real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDens_dPresNext; - //real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens_dPres; real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDensNext[Deriv::dP]; real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens[Deriv::dP]; for( integer ic = 0; ic < NC; ++ic ) { - //dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDens_dCompDensNext[ic]; - //dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens_dCompDens[ic]; dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDensNext[Deriv::dC+ic]; dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens[Deriv::dC+ic]; } @@ -714,8 +318,6 @@ PressureRelationKernel:: arrayView1d< real64 const > const & wellElemPressure, arrayView1d< real64 const > const & wellElemTotalMassDens, arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, bool & controlHasSwitched, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -735,35 +337,17 @@ PressureRelationKernel:: wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ); arrayView1d< real64 const > const & dCurrentBHP = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() ); - // tjb - remove - real64 const & dCurrentBHP_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); - arrayView1d< real64 const > const & dCurrentBHP_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHP_dCompDensString() ); arrayView1d< real64 const > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); arrayView2d< real64 const > const & dCurrentPhaseVolRate = wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() ); - // tjb - remove - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dPresString() ); - arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens = - wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dCompDensString() ); - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRate_dRateString() ); real64 const & currentTotalVolRate = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ); arrayView1d< real64 const > const & dCurrentTotalVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() ); - // tjb - remove - real64 const & dCurrentTotalVolRate_dPres = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dPresString() ); - arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens = - wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dCompDensString() ); - real64 const & dCurrentTotalVolRate_dRate = - wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRate_dRateString() ); + real64 const & massDensity = wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() ); @@ -793,30 +377,22 @@ PressureRelationKernel:: switchControl.max( 1 ); } ControlEquationHelper::compute< NC, IS_THERMAL >( rankOffset, - newControl, - targetPhaseIndex, - targetBHP, - targetPhaseRate, - targetTotalRate, - targetMassRate, - currentBHP, - dCurrentBHP, - dCurrentBHP_dPres, - dCurrentBHP_dCompDens, - currentPhaseVolRate, - dCurrentPhaseVolRate, - dCurrentPhaseVolRate_dPres, - dCurrentPhaseVolRate_dCompDens, - dCurrentPhaseVolRate_dRate, - currentTotalVolRate, - dCurrentTotalVolRate, - dCurrentTotalVolRate_dPres, - dCurrentTotalVolRate_dCompDens, - dCurrentTotalVolRate_dRate, - massDensity, - wellElemDofNumber[iwelemControl], - localMatrix, - localRhs ); + newControl, + targetPhaseIndex, + targetBHP, + targetPhaseRate, + targetTotalRate, + targetMassRate, + currentBHP, + dCurrentBHP, + currentPhaseVolRate, + dCurrentPhaseVolRate, + currentTotalVolRate, + dCurrentTotalVolRate, + massDensity, + wellElemDofNumber[iwelemControl], + localMatrix, + localRhs ); // TODO: for consistency, we should assemble here, not in compute... } @@ -826,21 +402,17 @@ PressureRelationKernel:: real64 localPresRel = 0; real64 localPresRelJacobian[2*(NC+1+IS_THERMAL)]{}; - compute< NC, IS_THERMAL >( - wellElemGravCoef[iwelem], - wellElemGravCoef[iwelemNext], - wellElemPressure[iwelem], - wellElemPressure[iwelemNext], - wellElemTotalMassDens[iwelem], - wellElemTotalMassDens[iwelemNext], - dWellElemTotalMassDens[iwelem], - dWellElemTotalMassDens[iwelemNext], - dWellElemTotalMassDens_dPres[iwelem], - dWellElemTotalMassDens_dPres[iwelemNext], - dWellElemTotalMassDens_dCompDens[iwelem], - dWellElemTotalMassDens_dCompDens[iwelemNext], - localPresRel, - localPresRelJacobian ); + compute< NC, IS_THERMAL >( + wellElemGravCoef[iwelem], + wellElemGravCoef[iwelemNext], + wellElemPressure[iwelem], + wellElemPressure[iwelemNext], + wellElemTotalMassDens[iwelem], + wellElemTotalMassDens[iwelemNext], + dWellElemTotalMassDens[iwelem], + dWellElemTotalMassDens[iwelemNext], + localPresRel, + localPresRelJacobian ); // local working variables and arrays @@ -855,10 +427,10 @@ PressureRelationKernel:: dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dC + ic; dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL) + ic+1] = wellElemDofNumber[iwelem] + COFFSET_WJ::dC + ic; } - if constexpr ( IS_THERMAL ) + if constexpr ( IS_THERMAL ) { dofColIndices[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = wellElemDofNumber[iwelemNext] + COFFSET_WJ::dT; - dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL)+NC+1] = wellElemDofNumber[iwelem] + COFFSET_WJ::dT; + dofColIndices[TAG::CURRENT *(NC+1+IS_THERMAL)+NC+1] = wellElemDofNumber[iwelem] + COFFSET_WJ::dT; } if( eqnRowIndex >= 0 && eqnRowIndex < localMatrix.numRows() ) { @@ -877,24 +449,22 @@ PressureRelationKernel:: template \ void PressureRelationKernel:: \ launch< NC, IS_THERMAL >( localIndex const size, \ - globalIndex const rankOffset, \ - bool const isLocallyOwned, \ - localIndex const iwelemControl, \ - bool const isThermal, \ - integer const targetPhaseIndex, \ - WellControls const & wellControls, \ - real64 const & timeAtEndOfStep, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< real64 const > const & wellElemGravCoef, \ - arrayView1d< localIndex const > const & nextWellElemIndex, \ - arrayView1d< real64 const > const & wellElemPressure, \ - arrayView1d< real64 const > const & wellElemTotalMassDens, \ - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, \ - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, \ - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, \ - bool & controlHasSwitched, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) + globalIndex const rankOffset, \ + bool const isLocallyOwned, \ + localIndex const iwelemControl, \ + bool const isThermal, \ + integer const targetPhaseIndex, \ + WellControls const & wellControls, \ + real64 const & timeAtEndOfStep, \ + arrayView1d< globalIndex const > const & wellElemDofNumber, \ + arrayView1d< real64 const > const & wellElemGravCoef, \ + arrayView1d< localIndex const > const & nextWellElemIndex, \ + arrayView1d< real64 const > const & wellElemPressure, \ + arrayView1d< real64 const > const & wellElemTotalMassDens, \ + arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, \ + bool & controlHasSwitched, \ + CRSMatrixView< real64, globalIndex const > const & localMatrix, \ + arrayView1d< real64 > const & localRhs ) INST_PressureRelationKernel( 1, 0 ); INST_PressureRelationKernel( 1, 1 ); @@ -908,853 +478,6 @@ INST_PressureRelationKernel( 5, 0 ); INST_PressureRelationKernel( 5, 1 ); -/******************************** PerforationKernel ********************************/ - -template< integer NC, integer NP, integer IS_THERMAL > -GEOS_HOST_DEVICE -void -PerforationKernel:: - compute( bool const & disableReservoirToWellFlow, - real64 const & resPres, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & resPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dResPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dResCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & resPhaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dResPhaseCompFrac, - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > const & resPhaseRelPerm, - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > const & dResPhaseRelPerm_dPhaseVolFrac, - real64 const & wellElemGravCoef, - real64 const & wellElemPres, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompDens, - real64 const & wellElemTotalMassDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens, - real64 const & dWellElemTotalMassDens_dPres, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dWellElemCompFrac_dCompDens, - real64 const & perfGravCoef, - real64 const & trans, - arraySlice1d< real64 > const & compPerfRate, - arraySlice3d< real64 > const & dCompPerfRate, - arraySlice2d< real64 > const & dCompPerfRate_dPres, - arraySlice3d< real64 > const & dCompPerfRate_dComp ) -{ - using Deriv = multifluid::DerivativeOffset; - using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; - GEOS_UNUSED_VAR( dCompPerfRate ); - // local working variables and arrays - real64 pres[2]{}; - real64 dPres_dP[2]{}; - real64 dPres_dC[2][NC]{}; - real64 dFlux_dP[2]{}; - real64 dFlux_dC[2][NC]{}; - real64 dMult_dP[2]{}; - real64 dMult_dC[2][NC]{}; - real64 dPotDiff_dP[2]{}; - real64 dPotDiff_dC[2][NC]{}; - real64 multiplier[2]{}; - - real64 dResTotalMob_dC[NC]{}; - real64 dDens_dC[NC]{}; - real64 dVisc_dC[NC]{}; - real64 dRelPerm_dC[NC]{}; - real64 dMob_dC[NC]{}; - real64 dCompFrac_dCompDens[NC]{}; - - // local working variables - compact - // All derivative quantiites generated are stored in arrays using CP_Deriv offsets - // The input well/reservoir quantites use the Deriv offsets - // The arrays using the deriv offsets have extra column for dT in isothermal cases - - real64 dPres[2][CP_Deriv::nDer]{}; - real64 dFlux[2][CP_Deriv::nDer]{}; - real64 dMob[CP_Deriv::nDer]{}; - real64 dPotDiff[2][CP_Deriv::nDer]{}; - real64 dCompFrac[CP_Deriv::nDer]{}; - - // Step 1: reset the perforation rates - // tjb - remove when safe - for( integer ic = 0; ic < NC; ++ic ) - { - compPerfRate[ic] = 0.0; - for( integer ke = 0; ke < 2; ++ke ) - { - dCompPerfRate_dPres[ke][ic] = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dCompPerfRate_dComp[ke][ic][jc] = 0.0; - } - } - } - for( integer ic = 0; ic < NC; ++ic ) - { - compPerfRate[ic] = 0.0; - for( integer ke = 0; ke < 2; ++ke ) - { - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dCompPerfRate[ke][ic][jc] = 0.0; - } - } - } - - // Step 2: copy the variables from the reservoir and well element - - // a) get reservoir variables - - pres[TAG::RES] = resPres; - dPres_dP[TAG::RES] = 1.0; - dPres[TAG::RES][CP_Deriv::dP] = 1.0; - multiplier[TAG::RES] = 1.0; - - // Here in the absence of a buoyancy term we assume that the reservoir cell is perforated at its center - // TODO: add a buoyancy term for the reservoir side here - - - // b) get well variables - - pres[TAG::WELL] = wellElemPres; - dPres_dP[TAG::WELL] = 1.0; - dPres[TAG::WELL][CP_Deriv::dP] = 1.0; - multiplier[TAG::WELL] = -1.0; - - real64 const gravD = ( perfGravCoef - wellElemGravCoef ); - - pres[TAG::WELL] += wellElemTotalMassDens * gravD; - // Note RHS uses CP_Deriv while LHS uses Deriv !!! - dPres_dP[TAG::WELL] += dWellElemTotalMassDens_dPres * gravD; - dPres[TAG::WELL][CP_Deriv::dP] += dWellElemTotalMassDens_dPres * gravD; - if constexpr ( IS_THERMAL ) - { - dPres[TAG::WELL][CP_Deriv::dT] += dWellElemTotalMassDens[Deriv::dT] * gravD; - } - for( integer ic = 0; ic < NC; ++ic ) - { - dPres_dC[TAG::WELL][ic] += dWellElemTotalMassDens_dCompDens[ic] * gravD; - dPres[TAG::WELL][CP_Deriv::dC+ic] += dWellElemTotalMassDens[Deriv::dC+ic] * gravD; - } - - - - // Step 3: compute potential difference - - real64 potDiff = 0.0; - for( integer i = 0; i < 2; ++i ) - { - potDiff += multiplier[i] * trans * pres[i]; - dPotDiff_dP[i] += multiplier[i] * trans * dPres_dP[i]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dPotDiff_dC[i][ic] += multiplier[i] * trans * dPres_dC[i][ic]; - } - // LHS & RHS both use CP_Deriv - for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) - { - dPotDiff[i][ic] += multiplier[i] * trans * dPres[i][ic]; - } - } - - - // Step 4: upwinding based on the flow direction - - real64 flux = 0.0; - if( potDiff >= 0 ) // ** reservoir cell is upstream ** - { - - // loop over phases, compute and upwind phase flux - // and sum contributions to each component's perforation rate - for( integer ip = 0; ip < NP; ++ip ) - { - - // skip the rest of the calculation if the phase is absent - // or if crossflow is disabled for injectors - bool const phaseExists = (resPhaseVolFrac[ip] > 0); - if( !phaseExists || disableReservoirToWellFlow ) - { - continue; - } - - // here, we have to recompute the reservoir phase mobility (not including density) - - // density - real64 const resDens = resPhaseDens[ip]; - real64 dDens[CP_Deriv::nDer]{}; - - real64 const dResDens_dP = dResPhaseDens[ip][Deriv::dP]; - dDens[CP_Deriv::dP] = dResPhaseDens[ip][Deriv::dP]; - if constexpr ( IS_THERMAL ) - { - dDens[CP_Deriv::dT] = dResPhaseDens[ip][Deriv::dT]; - } - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseDens[ip], - dDens_dC, - Deriv::dC ); - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseDens[ip], - &dDens[CP_Deriv::dC], - Deriv::dC ); - // viscosity - real64 const resVisc = resPhaseVisc[ip]; - real64 dVisc[CP_Deriv::nDer]{}; - real64 const dResVisc_dP = dResPhaseVisc[ip][Deriv::dP]; - dVisc[CP_Deriv::dP] = dResPhaseVisc[ip][Deriv::dP]; - if constexpr ( IS_THERMAL ) - { - dVisc[CP_Deriv::dT] = dResPhaseVisc[ip][Deriv::dT]; - } - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseVisc[ip], - dVisc_dC, - Deriv::dC ); - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseVisc[ip], - &dVisc[CP_Deriv::dC], - Deriv::dC ); - - // relative permeability - real64 const resRelPerm = resPhaseRelPerm[ip]; - real64 dRelPerm[CP_Deriv::nDer]{}; - real64 dResRelPerm_dP = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] = 0; - } - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dRelPerm[jc]=0; - } - for( integer jp = 0; jp < NP; ++jp ) - { - real64 const dResRelPerm_dS = dResPhaseRelPerm_dPhaseVolFrac[ip][jp]; - dResRelPerm_dP += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - if constexpr ( IS_THERMAL ) - { - dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dT]; - } - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; - dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; - } - } - - // compute the reservoir phase mobility, including phase density - real64 const resPhaseMob = resDens * resRelPerm / resVisc; - real64 const dResPhaseMob_dPres = dResRelPerm_dP * resDens / resVisc - + resPhaseMob * (dResDens_dP / resDens - dResVisc_dP / resVisc); - for( integer jc = 0; jc < NC; ++jc ) - { - dMob_dC[jc] = dRelPerm_dC[jc] * resDens / resVisc - + resPhaseMob * (dDens_dC[jc] / resDens - dVisc_dC[jc] / resVisc); - } - // Handles all dependencies - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dMob[jc] = dRelPerm[jc] * resDens / resVisc - + resPhaseMob * (dDens[jc] / resDens - dVisc[jc] / resVisc); - } - - // compute the phase flux and derivatives using upstream cell mobility - flux = resPhaseMob * potDiff; - dFlux_dP[TAG::RES] = dResPhaseMob_dPres * potDiff + resPhaseMob * dPotDiff_dP[TAG::RES]; - dFlux_dP[TAG::WELL] = resPhaseMob * dPotDiff_dP[TAG::WELL]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dFlux_dC[TAG::RES][ic] = dMob_dC[ic] * potDiff + resPhaseMob * dPotDiff_dC[TAG::RES][ic]; - dFlux_dC[TAG::WELL][ic] = resPhaseMob * dPotDiff_dC[TAG::WELL][ic]; - } - // Handles all dependencies - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dFlux[TAG::RES][jc] = dMob[jc] * potDiff + resPhaseMob * dPotDiff[TAG::RES][jc]; - dFlux[TAG::WELL][jc] = resPhaseMob * dPotDiff[TAG::WELL][jc]; - } - // increment component fluxes - for( integer ic = 0; ic < NC; ++ic ) - { - compPerfRate[ic] += flux * resPhaseCompFrac[ip][ic]; - - dCompPerfRate_dPres[TAG::RES][ic] += resPhaseCompFrac[ip][ic] * dFlux_dP[TAG::RES]; - dCompPerfRate_dPres[TAG::RES][ic] += dResPhaseCompFrac[ip][ic][Deriv::dP] * flux; - dCompPerfRate_dPres[TAG::WELL][ic] += resPhaseCompFrac[ip][ic] * dFlux_dP[TAG::WELL]; - - applyChainRule( NC, - dResCompFrac_dCompDens, - dResPhaseCompFrac[ip][ic], - dCompFrac_dCompDens, - Deriv::dC ); - - for( integer jc = 0; jc < NC; ++jc ) - { - dCompPerfRate_dComp[TAG::RES][ic][jc] += dFlux_dC[TAG::RES][jc] * resPhaseCompFrac[ip][ic]; - dCompPerfRate_dComp[TAG::RES][ic][jc] += flux * dCompFrac_dCompDens[jc]; - dCompPerfRate_dComp[TAG::WELL][ic][jc] += dFlux_dC[TAG::WELL][jc] * resPhaseCompFrac[ip][ic]; - } - } - // increment component fluxes - for( integer ic = 0; ic < NC; ++ic ) - { - // Note this needs to be uncommented out - //compPerfRate[ic] += flux * resPhaseCompFrac[ip][ic]; - dCompFrac[CP_Deriv::dP] = dResPhaseCompFrac[ip][ic][Deriv::dP]; - if constexpr (IS_THERMAL) - { - dCompFrac[CP_Deriv::dT] = dResPhaseCompFrac[ip][ic][Deriv::dT]; - } - - applyChainRule( NC, - dResCompFrac_dCompDens, - dResPhaseCompFrac[ip][ic], - &dCompFrac[CP_Deriv::dC], - Deriv::dC ); - - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dCompPerfRate[TAG::RES][ic][jc] += dFlux[TAG::RES][jc] * resPhaseCompFrac[ip][ic]; - dCompPerfRate[TAG::RES][ic][jc] += flux * dCompFrac[jc]; - dCompPerfRate[TAG::WELL][ic][jc] += dFlux[TAG::WELL][jc] * resPhaseCompFrac[ip][ic]; - } - } - } - - // tjb- remove when safe - for( integer ic = 0; ic < NC; ic++ ) - { - assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic] ) < FLT_EPSILON ); - assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic] ) < FLT_EPSILON ); - for( integer jc = 0; jc < NC; ++jc ) - { - assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc] ) < FLT_EPSILON ); - assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc] ) < FLT_EPSILON ); - } - } - } - else // ** well is upstream ** - { - - real64 resTotalMob = 0.0; - real64 dResTotalMob_dP = 0.0; - - // we re-compute here the total mass (when useMass == 1) or molar (when useMass == 0) density - real64 wellElemTotalDens = 0; - for( integer ic = 0; ic < NC; ++ic ) - { - wellElemTotalDens += wellElemCompDens[ic]; - } - - // first, compute the reservoir total mobility (excluding phase density) - for( integer ip = 0; ip < NP; ++ip ) - { - - // skip the rest of the calculation if the phase is absent - bool const phaseExists = (resPhaseVolFrac[ip] > 0); - if( !phaseExists ) - { - continue; - } - - // viscosity - real64 const resVisc = resPhaseVisc[ip]; - real64 dVisc[CP_Deriv::nDer]{}; - real64 const dResVisc_dP = dResPhaseVisc[ip][Deriv::dP]; - dVisc[CP_Deriv::dP] = dResPhaseVisc[ip][Deriv::dP]; - if constexpr ( IS_THERMAL ) - { - dVisc[CP_Deriv::dT] = dResPhaseVisc[ip][Deriv::dT]; - } - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseVisc[ip], - dVisc_dC, - Deriv::dC ); - applyChainRule( NC, dResCompFrac_dCompDens, - dResPhaseVisc[ip], - &dVisc[CP_Deriv::dC], - Deriv::dC ); - - - // relative permeability - real64 const resRelPerm = resPhaseRelPerm[ip]; - real64 dRelPerm[CP_Deriv::nDer]{}; - real64 dResRelPerm_dP = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] = 0; - } - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dRelPerm[jc]=0; - } - for( integer jp = 0; jp < NP; ++jp ) - { - real64 const dResRelPerm_dS = dResPhaseRelPerm_dPhaseVolFrac[ip][jp]; - dResRelPerm_dP += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dP]; - if constexpr ( IS_THERMAL ) - { - dRelPerm[CP_Deriv::dT] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dT]; - } - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; - dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * dResPhaseVolFrac[jp][Deriv::dC+jc]; - } - } - // increment total mobility - resTotalMob += resRelPerm / resVisc; - - dResTotalMob_dP += ( dResRelPerm_dP * resVisc - resRelPerm * dResVisc_dP ) - / ( resVisc * resVisc ); - for( integer ic = 0; ic < NC; ++ic ) - { - dResTotalMob_dC[ic] += ( dRelPerm_dC[ic] * resVisc - resRelPerm * dVisc_dC[ic] ) - / ( resVisc * resVisc ); - } - // Handles all dependencies - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dMob[jc] += (dRelPerm[jc] *resVisc - resRelPerm * dVisc[jc] ) - / ( resVisc * resVisc); - } - } - - // compute a potdiff multiplier = wellElemTotalDens * resTotalMob - // wellElemTotalDens is a mass density if useMass == 1 and a molar density otherwise - real64 const mult = wellElemTotalDens * resTotalMob; - dMult_dP[TAG::RES] = wellElemTotalDens * dResTotalMob_dP; - dMult_dP[TAG::WELL] = 0.0; // because totalDens does not depend on pressure - for( integer ic = 0; ic < NC; ++ic ) - { - dMult_dC[TAG::RES][ic] = wellElemTotalDens * dResTotalMob_dC[ic]; - dMult_dC[TAG::WELL][ic] = resTotalMob; - } - - real64 dMult[2][CP_Deriv::nDer]{}; - dMult[TAG::WELL][CP_Deriv::dP] = 0.0; - if constexpr ( IS_THERMAL ) - { - dMult[TAG::WELL][CP_Deriv::dT] = 0.0; - } - for( integer ic = 0; ic < NC; ++ic ) - { - dMult[TAG::WELL][CP_Deriv::dC+ic] = resTotalMob; - } - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dMult[TAG::RES][jc] = wellElemTotalDens * dMob[jc]; - } - - - // compute the volumetric flux and derivatives using upstream cell mobility - flux = mult * potDiff; - dFlux_dP[TAG::RES] = dMult_dP[TAG::RES] * potDiff + mult * dPotDiff_dP[TAG::RES]; - dFlux_dP[TAG::WELL] = dMult_dP[TAG::WELL] * potDiff + mult * dPotDiff_dP[TAG::WELL]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dFlux_dC[TAG::RES][ic] = dMult_dC[TAG::RES][ic] * potDiff + mult * dPotDiff_dC[TAG::RES][ic]; - dFlux_dC[TAG::WELL][ic] = dMult_dC[TAG::WELL][ic] * potDiff + mult * dPotDiff_dC[TAG::WELL][ic]; - } - - for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) - { - dFlux[TAG::RES][ic] = dMult[TAG::RES][ic] * potDiff + mult * dPotDiff[TAG::RES][ic]; - dFlux[TAG::WELL][ic] = dMult[TAG::WELL][ic] * potDiff + mult * dPotDiff[TAG::WELL][ic]; - } - // compute component fluxes - for( integer ic = 0; ic < NC; ++ic ) - { - compPerfRate[ic] += wellElemCompFrac[ic] * flux; - dCompPerfRate_dPres[TAG::RES][ic] = wellElemCompFrac[ic] * dFlux_dP[TAG::RES]; - dCompPerfRate_dPres[TAG::WELL][ic] = wellElemCompFrac[ic] * dFlux_dP[TAG::WELL]; - - for( integer jc = 0; jc < NC; ++jc ) - { - dCompPerfRate_dComp[TAG::RES][ic][jc] += wellElemCompFrac[ic] * dFlux_dC[TAG::RES][jc]; - dCompPerfRate_dComp[TAG::WELL][ic][jc] += wellElemCompFrac[ic] * dFlux_dC[TAG::WELL][jc]; - dCompPerfRate_dComp[TAG::WELL][ic][jc] += dWellElemCompFrac_dCompDens[ic][jc] * flux; - } - } - for( integer ic = 0; ic < NC; ++ic ) - { - // Note this needs to be include below when this code above is removed - //compPerfRate[ic] += wellElemCompFrac[ic] * flux; - for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) - { - dCompPerfRate[TAG::RES][ic][jc] = wellElemCompFrac[ic] * dFlux[TAG::RES][jc]; - } - } - for( integer ic = 0; ic < NC; ++ic ) - { - dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] = wellElemCompFrac[ic] * dFlux[TAG::WELL][CP_Deriv::dP]; - if constexpr ( IS_THERMAL ) - { - dCompPerfRate[TAG::WELL][ic][CP_Deriv::dT] = wellElemCompFrac[ic] * dFlux[TAG::WELL][CP_Deriv::dT]; - } - for( integer jc = 0; jc < NC; ++jc ) - { - dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] += wellElemCompFrac[ic] * dFlux[TAG::WELL][CP_Deriv::dC+jc]; - dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] += dWellElemCompFrac_dCompDens[ic][jc] * flux; - } - } - // tjb- remove when safe - for( integer ic = 0; ic < NC; ic++ ) - { - assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::RES][ic] ) < FLT_EPSILON ); - assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dP] -dCompPerfRate_dPres[TAG::WELL][ic] ) < FLT_EPSILON ); - for( integer jc = 0; jc < NC; ++jc ) - { - assert( fabs( dCompPerfRate[TAG::RES][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::RES][ic][jc] ) < FLT_EPSILON ); - assert( fabs( dCompPerfRate[TAG::WELL][ic][CP_Deriv::dC+jc] -dCompPerfRate_dComp[TAG::WELL][ic][jc] ) < FLT_EPSILON ); - } - } - } -} - -template< integer NC, integer NP, integer IS_THERMAL > -void -PerforationKernel:: - launch( localIndex const size, - bool const disableReservoirToWellFlow, - ElementViewConst< arrayView1d< real64 const > > const & resPres, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dResPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dResCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & resPhaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dResPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & resPhaseRelPerm, - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const & dResPhaseRelPerm_dPhaseVolFrac, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< real64 const > const & wellElemPres, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, - arrayView1d< real64 const > const & wellElemTotalMassDens, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView1d< real64 const > const & perfGravCoef, - arrayView1d< localIndex const > const & perfWellElemIndex, - arrayView1d< real64 const > const & perfTrans, - arrayView1d< localIndex const > const & resElementRegion, - arrayView1d< localIndex const > const & resElementSubRegion, - arrayView1d< localIndex const > const & resElementIndex, - arrayView2d< real64 > const & compPerfRate, - arrayView4d< real64 > const & dCompPerfRate, - arrayView3d< real64 > const & dCompPerfRate_dPres, - arrayView4d< real64 > const & dCompPerfRate_dComp ) -{ - - // loop over the perforations to compute the perforation rates - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) - { - - // get the index of the reservoir elem - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - - // get the index of the well elem - localIndex const iwelem = perfWellElemIndex[iperf]; - - compute< NC, NP, IS_THERMAL >( disableReservoirToWellFlow, - resPres[er][esr][ei], - resPhaseVolFrac[er][esr][ei], - dResPhaseVolFrac[er][esr][ei], - dResCompFrac_dCompDens[er][esr][ei], - resPhaseDens[er][esr][ei][0], - dResPhaseDens[er][esr][ei][0], - resPhaseVisc[er][esr][ei][0], - dResPhaseVisc[er][esr][ei][0], - resPhaseCompFrac[er][esr][ei][0], - dResPhaseCompFrac[er][esr][ei][0], - resPhaseRelPerm[er][esr][ei][0], - dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0], - wellElemGravCoef[iwelem], - wellElemPres[iwelem], - wellElemCompDens[iwelem], - wellElemTotalMassDens[iwelem], - dWellElemTotalMassDens[iwelem], - dWellElemTotalMassDens_dPres[iwelem], - dWellElemTotalMassDens_dCompDens[iwelem], - wellElemCompFrac[iwelem], - dWellElemCompFrac_dCompDens[iwelem], - perfGravCoef[iperf], - perfTrans[iperf], - compPerfRate[iperf], - dCompPerfRate[iperf], - dCompPerfRate_dPres[iperf], - dCompPerfRate_dComp[iperf] ); - - } ); -} - -#define INST_PerforationKernel( NC, NP, IS_THERMAL ) \ - template \ - void PerforationKernel:: \ - launch< NC, NP, IS_THERMAL >( localIndex const size, \ - bool const disableReservoirToWellFlow, \ - ElementViewConst< arrayView1d< real64 const > > const & resPres, \ - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dResPhaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dResCompFrac_dCompDens, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseDens, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseDens, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseVisc, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseVisc, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & resPhaseCompFrac, \ - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dResPhaseCompFrac, \ - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & resPhaseRelPerm, \ - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const & dResPhaseRelPerm_dPhaseVolFrac, \ - arrayView1d< real64 const > const & wellElemGravCoef, \ - arrayView1d< real64 const > const & wellElemPres, \ - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, \ - arrayView1d< real64 const > const & wellElemTotalMassDens, \ - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, \ - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, \ - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, \ - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, \ - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, \ - arrayView1d< real64 const > const & perfGravCoef, \ - arrayView1d< localIndex const > const & perfWellElemIndex, \ - arrayView1d< real64 const > const & perfTrans, \ - arrayView1d< localIndex const > const & resElementRegion, \ - arrayView1d< localIndex const > const & resElementSubRegion, \ - arrayView1d< localIndex const > const & resElementIndex, \ - arrayView2d< real64 > const & compPerfRate, \ - arrayView4d< real64 > const & dCompPerfRate, \ - arrayView3d< real64 > const & dCompPerfRate_dPres, \ - arrayView4d< real64 > const & dCompPerfRate_dComp ) - -INST_PerforationKernel( 1, 2, 0 ); -INST_PerforationKernel( 2, 2, 0 ); -INST_PerforationKernel( 3, 2, 0 ); -INST_PerforationKernel( 4, 2, 0 ); -INST_PerforationKernel( 5, 2, 0 ); -INST_PerforationKernel( 1, 3, 0 ); -INST_PerforationKernel( 2, 3, 0 ); -INST_PerforationKernel( 3, 3, 0 ); -INST_PerforationKernel( 4, 3, 0 ); -INST_PerforationKernel( 5, 3, 0 ); -INST_PerforationKernel( 1, 2, 1 ); -INST_PerforationKernel( 2, 2, 1 ); -INST_PerforationKernel( 3, 2, 1 ); -INST_PerforationKernel( 4, 2, 1 ); -INST_PerforationKernel( 5, 2, 1 ); -INST_PerforationKernel( 1, 3, 1 ); -INST_PerforationKernel( 2, 3, 1 ); -INST_PerforationKernel( 3, 3, 1 ); -INST_PerforationKernel( 4, 3, 1 ); -INST_PerforationKernel( 5, 3, 1 ); -/******************************** AccumulationKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -AccumulationKernel:: - compute( integer const numPhases, - real64 const & volume, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dPhaseCompFrac, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac_n, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens_n, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac_n, - real64 ( & localAccum )[NC], - real64 ( & localAccumJacobian )[NC][NC + 1] ) -{ - using Deriv = multifluid::DerivativeOffset; - - // temporary work arrays - real64 dPhaseAmount_dC[NC]{}; - real64 dPhaseCompFrac_dC[NC]{}; - - // reset the local values - for( integer i = 0; i < NC; ++i ) - { - localAccum[i] = 0.0; - for( integer j = 0; j < NC+1; ++j ) - { - localAccumJacobian[i][j] = 0.0; - } - } - - // sum contributions to component accumulation from each phase - for( integer ip = 0; ip < numPhases; ++ip ) - { - real64 const phaseAmountNew = volume * phaseVolFrac[ip] * phaseDens[ip]; - real64 const phaseAmount_n = volume * phaseVolFrac_n[ip] * phaseDens_n[ip]; - - real64 const dPhaseAmount_dP = volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] - + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); - - // assemble density dependence - applyChainRule( NC, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); - for( integer jc = 0; jc < NC; ++jc ) - { - dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] - + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; - dPhaseAmount_dC[jc] *= volume; - } - - // ic - index of component whose conservation equation is assembled - // (i.e. row number in local matrix) - for( integer ic = 0; ic < NC; ++ic ) - { - real64 const phaseCompAmountNew = phaseAmountNew * phaseCompFrac[ip][ic]; - real64 const phaseCompAmount_n = phaseAmount_n * phaseCompFrac_n[ip][ic]; - - real64 const dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] - + phaseAmountNew * dPhaseCompFrac[ip][ic][Deriv::dP]; - - localAccum[ic] += phaseCompAmountNew - phaseCompAmount_n; - localAccumJacobian[ic][0] += dPhaseCompAmount_dP; - - // jc - index of component w.r.t. whose compositional var the derivative is being taken - // (i.e. col number in local matrix) - - // assemble phase composition dependence - applyChainRule( NC, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dPhaseCompFrac_dC, Deriv::dC ); - for( integer jc = 0; jc < NC; ++jc ) - { - real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmountNew - + phaseCompFrac[ip][ic] * dPhaseAmount_dC[jc]; - localAccumJacobian[ic][jc + 1] += dPhaseCompAmount_dC; - } - } - } -} - -template< integer NC > -void -AccumulationKernel:: - launch( localIndex const size, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< integer const > const & wellElemGhostRank, - arrayView1d< real64 const > const & wellElemVolume, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac, - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - - using namespace compositionalMultiphaseUtilities; - - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - - if( wellElemGhostRank[iwelem] >= 0 ) - { - return; - } - - real64 localAccum[NC]{}; - real64 localAccumJacobian[NC][NC+1]{}; - - compute< NC >( numPhases, - wellElemVolume[iwelem], - wellElemPhaseVolFrac[iwelem], - dWellElemPhaseVolFrac[iwelem], - dWellElemCompFrac_dCompDens[iwelem], - wellElemPhaseDens[iwelem][0], - dWellElemPhaseDens[iwelem][0], - wellElemPhaseCompFrac[iwelem][0], - dWellElemPhaseCompFrac[iwelem][0], - wellElemPhaseVolFrac_n[iwelem], - wellElemPhaseDens_n[iwelem][0], - wellElemPhaseCompFrac_n[iwelem][0], - localAccum, - localAccumJacobian ); - - // set the equation row indices to be the mass balance equations for all components - localIndex eqnRowIndices[NC]{}; - for( integer ic = 0; ic < NC; ++ic ) - { - eqnRowIndices[ic] = wellElemDofNumber[iwelem] + ROFFSET::MASSBAL + ic - rankOffset; - } - - // set DOF col indices for this block - globalIndex dofColIndices[NC+1]{}; - for( integer idof = 0; idof < NC+1; ++idof ) - { - dofColIndices[idof] = wellElemDofNumber[iwelem] + COFFSET::DPRES + idof; - } - - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, localAccumJacobian, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, localAccum ); - } - - // add contribution to residual and jacobian - for( integer ic = 0; ic < NC; ++ic ) - { - localRhs[eqnRowIndices[ic]] += localAccum[ic]; - localMatrix.addToRow< serialAtomic >( eqnRowIndices[ic], - dofColIndices, - localAccumJacobian[ic], - NC+1 ); - } - } ); -} - -#define INST_AccumulationKernel( NC ) \ - template \ - void AccumulationKernel:: \ - launch< NC >( localIndex const size, \ - integer const numPhases, \ - globalIndex const rankOffset, \ - integer const useTotalMassEquation, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< integer const > const & wellElemGhostRank, \ - arrayView1d< real64 const > const & wellElemVolume, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, \ - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, \ - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, \ - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens, \ - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens, \ - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac, \ - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n, \ - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n, \ - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_AccumulationKernel( 1 ); -INST_AccumulationKernel( 2 ); -INST_AccumulationKernel( 3 ); -INST_AccumulationKernel( 4 ); -INST_AccumulationKernel( 5 ); - /******************************** VolumeBalanceKernel ********************************/ template< integer NC > @@ -1773,7 +496,7 @@ VolumeBalanceKernel:: localVolBalance = 1.0; for( integer ic = 0; ic < NC+1; ++ic ) { - localVolBalanceJacobian[ic] = 0.0; + localVolBalanceJacobian[ic] = 0.0; } // sum contributions to component accumulation from each phase @@ -1974,10 +697,10 @@ PresTempCompFracInitializationKernel:: // use surface temperature from injection stream avgTemp = wellControls.getSurfaceTemperature(); } - else - { - // use temperature from injection stream - avgTemp = wellControls.getInjectionTemperature(); + else + { + // use temperature from injection stream + avgTemp = wellControls.getInjectionTemperature(); } // use comp frac from injection stream for( integer ic = 0; ic < numComps; ++ic ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index aea5ccd4bf8..f2b82b6ccd2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -119,7 +119,7 @@ struct RowOffset_WellJac< NC, 1 > static constexpr integer MASSBAL = 1; static constexpr integer VOLBAL = MASSBAL + NC; static constexpr integer ENERGYBAL = VOLBAL+1; -static constexpr integer nEqn = ENERGYBAL+1; + static constexpr integer nEqn = ENERGYBAL+1; }; /******************************** ControlEquationHelper ********************************/ @@ -157,18 +157,10 @@ struct ControlEquationHelper real64 const & targetMassRate, real64 const & currentBHP, arrayView1d< real64 const > const & dCurrentBHP, - real64 const & dCurrentBHP_dPres, - arrayView1d< real64 const > const & dCurrentBHP_dCompDens, arrayView1d< real64 const > const & currentPhaseVolRate, arrayView2d< real64 const > const & dCurrentPhaseVolRate, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dPres, - arrayView2d< real64 const > const & dCurrentPhaseVolRate_dCompDens, - arrayView1d< real64 const > const & dCurrentPhaseVolRate_dRate, real64 const & currentTotalVolRate, arrayView1d< real64 const > const & dCurrentTotalVolRate, - real64 const & dCurrentTotalVolRate_dPres, - arrayView1d< real64 const > const & dCurrentTotalVolRate_dCompDens, - real64 const & dCurrentTotalVolRate_dRate, real64 const & massDensity, globalIndex const dofNumber, CRSMatrixView< real64, globalIndex const > const & localMatrix, @@ -176,58 +168,6 @@ struct ControlEquationHelper }; -/******************************** FluxKernel ********************************/ - -struct FluxKernel -{ - - using TAG = compositionalMultiphaseWellKernels::ElemTag; - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - computeExit( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( &oneSidedFlux )[NC], - real64 ( &oneSidedFluxJacobian_dRate )[NC][1], - real64 ( &oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1] ); - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dt, - real64 const ( &compFlux )[NC], - real64 const ( &dCompFlux_dRate )[NC], - real64 const ( &dCompFlux_dPresUp )[NC], - real64 const ( &dCompFlux_dCompDensUp )[NC][NC], - real64 ( &localFlux )[2*NC], - real64 ( &localFluxJacobian_dRate )[2*NC][1], - real64 ( &localFluxJacobian_dPresCompUp )[2*NC][NC + 1] ); - - template< integer NC > - static void - launch( localIndex const size, - globalIndex const rankOffset, - integer const useTotalMassEquation, - WellControls const & wellControls, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< localIndex const > const & nextWellElemIndex, - arrayView1d< real64 const > const & connRate, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - /******************************** PressureRelationKernel ********************************/ struct PressureRelationKernel @@ -249,10 +189,6 @@ struct PressureRelationKernel real64 const & totalMassDensNext, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, - real64 const & dTotalMassDens_dPres, - real64 const & dTotalMassDens_dPresNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, real64 & localPresRel, real64 ( &localPresRelJacobian )[2*(NC+1+IS_THERMAL)] ); @@ -272,176 +208,12 @@ struct PressureRelationKernel arrayView1d< real64 const > const & wellElemPressure, arrayView1d< real64 const > const & wellElemTotalMassDens, arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, bool & controlHasSwitched, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); }; -/******************************** PerforationKernel ********************************/ - -struct PerforationKernel -{ - - using TAG = compositionalMultiphaseWellKernels::SubRegionTag; - - using CompFlowAccessors = - StencilAccessors< fields::flow::pressure, - fields::flow::phaseVolumeFraction, - fields::flow::dPhaseVolumeFraction, - fields::flow::dGlobalCompFraction_dGlobalCompDensity >; - - using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, - fields::multifluid::phaseDensity, - fields::multifluid::dPhaseDensity, - fields::multifluid::phaseViscosity, - fields::multifluid::dPhaseViscosity, - fields::multifluid::phaseCompFraction, - fields::multifluid::dPhaseCompFraction >; - - using RelPermAccessors = - StencilMaterialAccessors< RelativePermeabilityBase, - fields::relperm::phaseRelPerm, - fields::relperm::dPhaseRelPerm_dPhaseVolFraction >; - - - /** - * @brief The type for element-based non-constitutive data parameters. - * Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - - template< integer NC, integer NP, integer IS_THERMAL > - GEOS_HOST_DEVICE - inline - static void - compute( bool const & disableReservoirToWellFlow, - real64 const & resPres, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & resPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dResPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dResCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & resPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dResPhaseVisc, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & resPhaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dResPhaseCompFrac, - arraySlice1d< real64 const, relperm::USD_RELPERM - 2 > const & resPhaseRelPerm, - arraySlice2d< real64 const, relperm::USD_RELPERM_DS - 2 > const & dResPhaseRelPerm_dPhaseVolFrac, - real64 const & wellElemGravCoef, - real64 const & wellElemPres, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompDens, - real64 const & wellElemTotalMassDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens, - real64 const & dWellElemTotalMassDens_dPres, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dWellElemTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const & wellElemCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dWellElemCompFrac_dCompDens, - real64 const & perfGravCoef, - real64 const & trans, - arraySlice1d< real64 > const & compPerfRate, - arraySlice3d< real64 > const & dCompPerfRate, - arraySlice2d< real64 > const & dCompPerfRate_dPres, - arraySlice3d< real64 > const & dCompPerfRate_dComp ); - - template< integer NC, integer NP, integer IS_THERMAL > - static void - launch( localIndex const size, - bool const disableReservoirToWellFlow, - ElementViewConst< arrayView1d< real64 const > > const & resPres, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & resPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dResPhaseVolFrac_dComp, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dResCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & resPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dResPhaseVisc, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & resPhaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dResPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const & resPhaseRelPerm, - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const & dResPhaseRelPerm_dPhaseVolFrac, - arrayView1d< real64 const > const & wellElemGravCoef, - arrayView1d< real64 const > const & wellElemPres, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompDens, - arrayView1d< real64 const > const & wellElemTotalMassDens, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens, - arrayView1d< real64 const > const & dWellElemTotalMassDens_dPres, - arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens_dCompDens, - arrayView2d< real64 const, compflow::USD_COMP > const & wellElemCompFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView1d< real64 const > const & perfGravCoef, - arrayView1d< localIndex const > const & perfWellElemIndex, - arrayView1d< real64 const > const & perfTrans, - arrayView1d< localIndex const > const & resElementRegion, - arrayView1d< localIndex const > const & resElementSubRegion, - arrayView1d< localIndex const > const & resElementIndex, - arrayView2d< real64 > const & compPerfRate, - arrayView4d< real64 > const & dCompPerfRate, - arrayView3d< real64 > const & dCompPerfRate_dPres, - arrayView4d< real64 > const & dCompPerfRate_dComp ); - -}; - - -/******************************** AccumulationKernel ********************************/ - -struct AccumulationKernel -{ - - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( integer const numPhases, - real64 const & volume, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const & dCompFrac_dCompDens, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dPhaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > const & dPhaseCompFrac, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac_n, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseDens_n, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > const & phaseCompFrac_n, - real64 ( &localAccum )[NC], - real64 ( &localAccumJacobian )[NC][NC + 1] ); - - template< integer NC > - static void - launch( localIndex const size, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< integer const > const & wellElemGhostRank, - arrayView1d< real64 const > const & wellElemVolume, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_COMP_DC > const & dWellElemCompFrac_dCompDens, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const & dWellElemPhaseDens, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac, - arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > const & dWellElemPhaseCompFrac, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac_n, - arrayView3d< real64 const, multifluid::USD_PHASE > const & wellElemPhaseDens_n, - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const & wellElemPhaseCompFrac_n, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - /******************************** VolumeBalanceKernel ********************************/ struct VolumeBalanceKernel @@ -590,9 +362,7 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne m_phaseMassDens( fluid.phaseMassDensity() ), m_dPhaseMassDens( fluid.dPhaseMassDensity() ), m_totalMassDens( subRegion.getField< fields::well::totalMassDensity >() ), - m_dTotalMassDens( subRegion.getField< fields::well::dTotalMassDensity >() ), - m_dTotalMassDens_dPres( subRegion.getField< fields::well::dTotalMassDensity_dPressure >() ), - m_dTotalMassDens_dCompDens( subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >() ) + m_dTotalMassDens( subRegion.getField< fields::well::dTotalMassDensity >() ) {} /** @@ -617,31 +387,25 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne real64 & totalMassDens = m_totalMassDens[ei]; arraySlice1d< real64, compflow::USD_FLUID_DC - 1 > dTotalMassDens = m_dTotalMassDens[ei]; - real64 & dTotalMassDens_dPres = m_dTotalMassDens_dPres[ei]; - arraySlice1d< real64, compflow::USD_FLUID_DC - 1 > dTotalMassDens_dCompDens = m_dTotalMassDens_dCompDens[ei]; + real64 dMassDens_dC[numComp]{}; totalMassDens = 0.0; - dTotalMassDens[Deriv::dP]=0.0; - dTotalMassDens_dPres = 0.0; + dTotalMassDens[Deriv::dP]=0.0; for( integer ic = 0; ic < numComp; ++ic ) { - dTotalMassDens_dCompDens[ic] = 0.0; dTotalMassDens[Deriv::dC+ic]=0.0; } for( integer ip = 0; ip < numPhase; ++ip ) { totalMassDens += phaseVolFrac[ip] * phaseMassDens[ip]; - dTotalMassDens_dPres += dPhaseVolFrac[ip][Deriv::dP] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dP]; dTotalMassDens[Deriv::dP] += dPhaseVolFrac[ip][Deriv::dP] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dP]; applyChainRule( numComp, dCompFrac_dCompDens, dPhaseMassDens[ip], dMassDens_dC, Deriv::dC ); for( integer ic = 0; ic < numComp; ++ic ) { - dTotalMassDens_dCompDens[ic] += dPhaseVolFrac[ip][Deriv::dC+ic] * phaseMassDens[ip] - + phaseVolFrac[ip] * dMassDens_dC[ic]; dTotalMassDens[Deriv::dC+ic] += dPhaseVolFrac[ip][Deriv::dC+ic] * phaseMassDens[ip] + phaseVolFrac[ip] * dMassDens_dC[ic]; } @@ -669,8 +433,7 @@ class TotalMassDensityKernel : public isothermalCompositionalMultiphaseBaseKerne /// Views on total mass densities arrayView1d< real64 > m_totalMassDens; arrayView2d< real64, compflow::USD_FLUID_DC > m_dTotalMassDens; - arrayView1d< real64 > m_dTotalMassDens_dPres; - arrayView2d< real64, compflow::USD_FLUID_DC > m_dTotalMassDens_dCompDens; + }; @@ -860,11 +623,11 @@ class ResidualNormKernel : public solverBaseKernels::ResidualNormKernelBase< 1 > } -} + } + + // to make sure that everything still works well if the rate is zero, we add this check + normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); - // to make sure that everything still works well if the rate is zero, we add this check - normalizer = LvArray::math::max( normalizer, m_volume[iwelem] ); - // Step 4: compute the contribution to the residual real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer; if( val > stack.localValue[0] ) @@ -1157,7 +920,7 @@ class ElementBasedAssemblyKernel localIndex localRow = -1; /// Indices of the matrix rows/columns corresponding to the dofs in this element - globalIndex dofIndices[numDof]{}; // NC compdens + P + thermal + globalIndex dofIndices[numDof]{}; // NC compdens + P + thermal globalIndex eqnRowIndices[numDof]{}; globalIndex dofColIndices[numDof]{}; @@ -1190,7 +953,7 @@ class ElementBasedAssemblyKernel { // initialize the volume stack.volume = m_volume[ei]; - + // Note row/col indices needed to be consistent with layout of stack.localJacobian // Setup row equation indices for this element ( mass + vol + thermal if valid) @@ -1217,15 +980,15 @@ class ElementBasedAssemblyKernel stack.dofColIndices[numComp+1] = m_dofNumber[ei] + WJ_COFFSET::dT; } if( 1 ) - for( integer jc = 0; jc < numEqn; ++jc ) - { - stack.localResidual[jc] = 0.0; - for( integer ic = 0; ic < numDof; ++ic ) - { - stack.localJacobian[jc][ic] = 0.0; - } + for( integer jc = 0; jc < numEqn; ++jc ) + { + stack.localResidual[jc] = 0.0; + for( integer ic = 0; ic < numDof; ++ic ) + { + stack.localJacobian[jc][ic] = 0.0; + } - } + } } @@ -1261,7 +1024,7 @@ class ElementBasedAssemblyKernel arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; // temporary work arrays -real64 dPhaseAmount[FLUID_PROP_COFFSET::nDer]{}; + real64 dPhaseAmount[FLUID_PROP_COFFSET::nDer]{}; real64 dPhaseAmount_dC[numComp]{}; real64 dPhaseCompFrac_dC[numComp]{}; @@ -1273,18 +1036,18 @@ real64 dPhaseAmount[FLUID_PROP_COFFSET::nDer]{}; //remove tjb real64 const dPhaseAmount_dP = stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); -dPhaseAmount[FLUID_PROP_COFFSET::dP]=stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + dPhaseAmount[FLUID_PROP_COFFSET::dP]=stack.volume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] ); // assemble density dependence applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC ); -applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], &dPhaseAmount[FLUID_PROP_COFFSET::dC], Deriv::dC ); + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], &dPhaseAmount[FLUID_PROP_COFFSET::dC], Deriv::dC ); for( integer jc = 0; jc < numComp; ++jc ) { dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; dPhaseAmount_dC[jc] *= stack.volume; -dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] = dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] * phaseVolFrac[ip] + dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] = dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+jc]; dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] *= stack.volume; } @@ -1293,7 +1056,7 @@ dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] = dPhaseAmount[FLUID_PROP_COFFSET::dC+jc { assert( fabs( dPhaseAmount[FLUID_PROP_COFFSET::dC+ic] -dPhaseAmount_dC[ic] ) < FLT_EPSILON ); -} + } // ic - index of component whose conservation equation is assembled // (i.e. row number in local matrix) for( integer ic = 0; ic < numComp; ++ic ) @@ -1320,7 +1083,7 @@ dPhaseAmount[FLUID_PROP_COFFSET::dC+jc] = dPhaseAmount[FLUID_PROP_COFFSET::dC+jc stack.localJacobian[ic][jc + 1] += dPhaseCompAmount_dC; } } -if constexpr ( IS_THERMAL ) + if constexpr ( IS_THERMAL ) { dPhaseAmount[FLUID_PROP_COFFSET::dT] = stack.volume * (dPhaseVolFrac[ip][Deriv::dT] * phaseDens[ip] + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dT] ); for( integer ic = 0; ic < numComp; ++ic ) @@ -1354,7 +1117,7 @@ if constexpr ( IS_THERMAL ) * @param[inout] stack the stack variables * @param[in] phaseVolFractionSumKernelOp the function used to customize the kernel */ - + GEOS_HOST_DEVICE void computeVolumeBalance( localIndex const ei, StackVariables & stack ) const @@ -1378,7 +1141,7 @@ if constexpr ( IS_THERMAL ) { stack.localJacobian[numComp][jc+1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; } - + if constexpr ( IS_THERMAL) { stack.localJacobian[numComp][numComp+1] -= dPhaseVolFrac[ip][Deriv::dT]; @@ -1573,7 +1336,7 @@ class ElementBasedAssemblyKernelFactory { localIndex constexpr NUM_COMP = NC(); -integer constexpr istherm = IS_THERMAL(); + integer constexpr istherm = IS_THERMAL(); BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) @@ -1841,48 +1604,26 @@ class FaceBasedAssemblyKernel void computeExit( real64 const & dt, real64 const ( &compFlux )[NC ], - real64 const ( &dCompFlux_dRate )[NC ], - real64 const ( &dCompFlux_dPresUp )[NC ], - real64 const ( &dCompFlux_dCompDensUp )[NC ][NC], - real64 ( & oneSidedFlux )[NC], - real64 ( & oneSidedFluxJacobian_dRate )[NC][1], - real64 ( & oneSidedFluxJacobian_dPresCompUp )[NC][NC + 1], StackVariables & stack, real64 ( & dCompFlux)[NC][numDof] ) const { for( integer ic = 0; ic < NC; ++ic ) { - oneSidedFlux[ic] = -dt * compFlux[ic]; stack.localFlux[ic] = -dt * compFlux[ic]; // derivative with respect to rate - oneSidedFluxJacobian_dRate[ic][0] = -dt * dCompFlux_dRate[ic]; stack.localFluxJacobian_dQ[ic][0] = -dt * dCompFlux[ic][WJ_COFFSET::dQ]; - assert( fabs( dCompFlux[ic][WJ_COFFSET::dQ]- dCompFlux_dRate[ic] ) < FLT_EPSILON ); // derivative with respect to upstream pressure - oneSidedFluxJacobian_dPresCompUp[ic][0] = -dt * dCompFlux_dPresUp[ic]; stack.localFluxJacobian[ic][CP_Deriv::dP] = -dt * dCompFlux[ic][WJ_COFFSET::dP]; - assert( fabs( dCompFlux_dPresUp[ic]- dCompFlux[ic][WJ_COFFSET::dP] ) < FLT_EPSILON ); // derivatives with respect to upstream component densities for( integer jdof = 0; jdof < NC; ++jdof ) { - oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; stack.localFluxJacobian[ic][CP_Deriv::dC+jdof] = -dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; - assert( fabs( dCompFlux[ic][WJ_COFFSET::dC+jdof]- dCompFlux_dCompDensUp[ic][jdof] ) < FLT_EPSILON ); } if constexpr ( IS_THERMAL ) { stack.localFluxJacobian[ic][CP_Deriv::dT] = -dt * dCompFlux[ic][WJ_COFFSET::dT]; } } - for( integer ic = 0; ic < NC; ++ic ) - { - assert( fabs( stack.localFluxJacobian_dQ[ic][0]-oneSidedFluxJacobian_dRate[ic][0] ) < FLT_EPSILON ); - assert( fabs( stack.localFluxJacobian[ic][CP_Deriv::dP]-oneSidedFluxJacobian_dPresCompUp[ic][0] ) < FLT_EPSILON ); - for( integer jdof = 0; jdof < NC; ++jdof ) - { - assert( fabs( stack.localFluxJacobian[ic][CP_Deriv::dC+jdof]-oneSidedFluxJacobian_dPresCompUp[ic][jdof+1] ) < FLT_EPSILON ); - } - } } GEOS_HOST_DEVICE @@ -1890,33 +1631,19 @@ class FaceBasedAssemblyKernel void compute( real64 const & dt, real64 const ( &compFlux )[NC ], - real64 const ( &dCompFlux_dRate )[NC ], - real64 const ( &dCompFlux_dPresUp )[NC ], - real64 const ( &dCompFlux_dCompDensUp )[NC ][NC], - real64 ( & localFlux )[2*NC], - real64 ( & localFluxJacobian_dRate )[2*NC][1], - real64 ( & localFluxJacobian_dPresCompUp )[2*NC][NC + 1], StackVariables & stack, real64 ( & dCompFlux)[(NC )][numDof] ) const { // flux terms for( integer ic = 0; ic < NC; ++ic ) { - localFlux[TAG::NEXT *NC+ic] = dt * compFlux[ic]; - localFlux[TAG::CURRENT *NC+ic] = -dt * compFlux[ic]; stack.localFlux[TAG::NEXT * NC +ic] = dt * compFlux[ic]; stack.localFlux[TAG::CURRENT * NC +ic] = -dt * compFlux[ic]; // derivative with respect to rate - localFluxJacobian_dRate[TAG::NEXT * NC + ic][0] = dt * dCompFlux_dRate[ic]; - localFluxJacobian_dRate[TAG::CURRENT * NC +ic][0] = -dt * dCompFlux_dRate[ic]; stack.localFluxJacobian_dQ[TAG::NEXT * NC+ ic][0] = dt * dCompFlux[ic][WJ_COFFSET::dQ]; stack.localFluxJacobian_dQ[TAG::CURRENT * NC + +ic][0] = -dt * dCompFlux[ic][WJ_COFFSET::dQ]; - // derivative with respect to upstream pressure - localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][0] = dt * dCompFlux_dPresUp[ic]; - localFluxJacobian_dPresCompUp[TAG::CURRENT * NC+ ic][0] = -dt * dCompFlux_dPresUp[ic]; - stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dP] = dt * dCompFlux[ic][WJ_COFFSET::dP]; stack.localFluxJacobian[TAG::CURRENT * NC+ ic][CP_Deriv::dP] = -dt * dCompFlux[ic][WJ_COFFSET::dP]; @@ -1929,24 +1656,10 @@ class FaceBasedAssemblyKernel // derivatives with respect to upstream component densities for( integer jdof = 0; jdof < NC; ++jdof ) { - localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][jdof+1] = dt * dCompFlux_dCompDensUp[ic][jdof]; - localFluxJacobian_dPresCompUp[TAG::CURRENT * NC +ic][jdof+1] = -dt * dCompFlux_dCompDensUp[ic][jdof]; stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dC+jdof] = dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dC+jdof] = -dt * dCompFlux[ic][WJ_COFFSET::dC+jdof]; } } - for( integer ic = 0; ic < NC; ++ic ) - { - assert( fabs( stack.localFluxJacobian_dQ[TAG::NEXT * NC +ic][0]-localFluxJacobian_dRate[TAG::NEXT * NC +ic][0] ) < FLT_EPSILON ); - assert( fabs( stack.localFluxJacobian_dQ[TAG::CURRENT * NC +ic][0]-localFluxJacobian_dRate[TAG::CURRENT * NC +ic][0] ) < FLT_EPSILON ); - assert( fabs( stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dP]-localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][0] ) < FLT_EPSILON ); - assert( fabs( stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dP]-localFluxJacobian_dPresCompUp[TAG::CURRENT * NC +ic][0] ) < FLT_EPSILON ); - for( integer jdof = 0; jdof < NC; ++jdof ) - { - assert( fabs( stack.localFluxJacobian[TAG::NEXT * NC +ic][CP_Deriv::dC+jdof]-localFluxJacobian_dPresCompUp[TAG::NEXT * NC +ic][jdof+1] ) < FLT_EPSILON ); - assert( fabs( stack.localFluxJacobian[TAG::CURRENT * NC +ic][CP_Deriv::dC+jdof]-localFluxJacobian_dPresCompUp[TAG::CURRENT * NC +ic][jdof+1] ) < FLT_EPSILON ); - } - } } /** @@ -1968,21 +1681,15 @@ class FaceBasedAssemblyKernel // create local work arrays real64 compFracUp[NC]{}; - real64 dCompFrac_dCompDensUp[NC][NC]{}; - real64 compFlux[NC]{}; - real64 dCompFlux_dRate[NC]{}; - real64 dCompFlux_dPresUp[NC]{}; - real64 dCompFlux_dCompDensUp[NC][NC]{}; - real64 dComp[NC][NC]; real64 dCompFlux[NC][numDof]{}; for( integer ic = 0; ic < NC; ++ic ) { - for( integer jc = 0; jc < NC; ++jc ) - { - dComp[ic][jc]=0.0; - } + for( integer jc = 0; jc < NC; ++jc ) + { + dComp[ic][jc]=0.0; + } } // Step 1) decide the upwind well element @@ -2007,7 +1714,7 @@ class FaceBasedAssemblyKernel compFracUp[ic] = m_injection[ic]; for( integer jc = 0; jc < NC; ++jc ) { - dCompFrac_dCompDensUp[ic][jc] = 0.0; + //dComp[ic][jc] = 0.0; dComp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; } //for ( integer jc = 0 ;jc < WJ_COFFSET::nDer ; ++jc) @@ -2037,7 +1744,6 @@ class FaceBasedAssemblyKernel for( integer jc = 0; jc < NC; ++jc ) { dCompFlux[ic][WJ_COFFSET::dC+jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; - dCompFrac_dCompDensUp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; } } } @@ -2047,9 +1753,8 @@ class FaceBasedAssemblyKernel for( integer ic = 0; ic < NC; ++ic ) { compFlux[ic] = compFracUp[ic] * currentConnRate; - dCompFlux_dRate[ic] = compFracUp[ic]; dCompFlux[ic][WJ_COFFSET::dQ] = compFracUp[ic]; - dCompFlux_dPresUp[ic] = 0.0; // none of these quantities depend on pressure + // none of these quantities depend on pressure dCompFlux[ic][WJ_COFFSET::dP] = 0.0; if constexpr ( IS_THERMAL ) { @@ -2058,7 +1763,6 @@ class FaceBasedAssemblyKernel for( integer jc = 0; jc < NC; ++jc ) { dCompFlux[ic][WJ_COFFSET::dC+jc] = dCompFlux[ic][WJ_COFFSET::dC+jc] * currentConnRate; - dCompFlux_dCompDensUp[ic][jc] = dCompFrac_dCompDensUp[ic][jc] * currentConnRate; } } @@ -2068,140 +1772,20 @@ class FaceBasedAssemblyKernel if( iwelemNext < 0 ) // exit connection { // for this case, we only need NC mass conservation equations - // so we do not use the arrays initialized before the loop - real64 oneSidedFlux[NC]{}; - real64 oneSidedFluxJacobian_dRate[NC][1]{}; - real64 oneSidedFluxJacobian_dPresCompUp[NC][NC+1]{}; - computeExit ( m_dt, compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - oneSidedFlux, - oneSidedFluxJacobian_dRate, - oneSidedFluxJacobian_dPresCompUp, stack, dCompFlux ); - /* - globalIndex oneSidedEqnRowIndices[NC]{}; - globalIndex oneSidedDofColIndices_dPresCompUp[NC+1]{}; - globalIndex oneSidedDofColIndices_dRate = 0; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - oneSidedEqnRowIndices[ic] = stack.offsetUp + ROFFSET::MASSBAL + ic - m_rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - oneSidedDofColIndices_dRate = stack.offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - oneSidedDofColIndices_dPresCompUp[jdof] = stack.offsetUp + COFFSET::DPRES + jdof; - } - - if( m_useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, 1, oneSidedFluxJacobian_dRate, work ); - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC + 1, oneSidedFluxJacobian_dPresCompUp, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, oneSidedFlux ); - } - - for( integer i = 0; i < NC; ++i ) - { - if( oneSidedEqnRowIndices[i] >= 0 && oneSidedEqnRowIndices[i] < m_localMatrix.numRows() ) - { - m_localMatrix.addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - &oneSidedDofColIndices_dRate, - oneSidedFluxJacobian_dRate[i], - 1 ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices[i], - oneSidedDofColIndices_dPresCompUp, - oneSidedFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices[i]], oneSidedFlux[i] ); - } - } - */ } else // not an exit connection { - real64 localFlux[2*(NC)]{}; - real64 localFluxJacobian_dRate[2*NC][1]{}; - real64 localFluxJacobian_dPresCompUp[2*NC][NC+1]{}; - compute( m_dt, compFlux, - dCompFlux_dRate, - dCompFlux_dPresUp, - dCompFlux_dCompDensUp, - localFlux, - localFluxJacobian_dRate, - localFluxJacobian_dPresCompUp, stack, dCompFlux ); -stack.offsetNext = m_wellElemDofNumber[iwelemNext]; - /* - globalIndex eqnRowIndices[2*NC]{}; - globalIndex dofColIndices_dPresCompUp[NC+1]{}; - globalIndex dofColIndices_dRate = 0; - - stack.offsetNext = m_wellElemDofNumber[iwelemNext]; - - // jacobian indices - for( integer ic = 0; ic < NC; ++ic ) - { - // mass balance equations for all components - eqnRowIndices[TAG::NEXT *NC+ic] = stack.offsetNext + ROFFSET::MASSBAL + ic - m_rankOffset; - eqnRowIndices[TAG::CURRENT *NC+ic] = stack.offsetCurrent + ROFFSET::MASSBAL + ic - m_rankOffset; - } - - // in the dof ordering used in this class, there are 1 pressure dofs - // and NC compDens dofs before the rate dof in this block - localIndex const dRateColOffset = COFFSET::DCOMP + NC; - dofColIndices_dRate = stack.offsetCurrent + dRateColOffset; - - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - // dofs are the **upstream** pressure and component densities - dofColIndices_dPresCompUp[jdof] = stack.offsetUp + COFFSET::DPRES + jdof; - } - - if( m_useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NC + 1]{}; - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, 1, 2, localFluxJacobian_dRate, work ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NC, NC + 1, 2, localFluxJacobian_dPresCompUp, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( NC, NC, 2, localFlux ); - } - - for( integer i = 0; i < 2*NC; ++i ) - { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) - { - m_localMatrix.addToRow< parallelDeviceAtomic >( eqnRowIndices[i], - &dofColIndices_dRate, - localFluxJacobian_dRate[i], - 1 ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices_dPresCompUp, - localFluxJacobian_dPresCompUp[i], - NC+1 ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localFlux[i] ); - } - } - */ + stack.offsetNext = m_wellElemDofNumber[iwelemNext]; } compFluxKernelOp( iwelemNext, iwelemUp, currentConnRate, dComp ); @@ -2303,7 +1887,7 @@ class FaceBasedAssemblyKernelFactory isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { integer constexpr NUM_COMP = NC(); - + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index dfc9e919998..bc6a69022b9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -126,8 +126,6 @@ class PerforationFluxKernel m_wellElemCompDens( subRegion.getField< fields::well::globalCompDensity >()), m_wellElemTotalMassDens( subRegion.getField< fields::well::totalMassDensity >()), m_dWellElemTotalMassDens( subRegion.getField< fields::well::dTotalMassDensity >()), - m_dWellElemTotalMassDens_dPres( subRegion.getField< fields::well::dTotalMassDensity_dPressure >()), - m_dWellElemTotalMassDens_dCompDens( subRegion.getField< fields::well::dTotalMassDensity_dGlobalCompDensity >()), m_wellElemCompFrac( subRegion.getField< fields::well::globalCompFraction >()), m_dWellElemCompFrac_dCompDens( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >()), m_perfGravCoef( perforationData->getField< fields::well::gravityCoefficient >()), @@ -138,12 +136,10 @@ class PerforationFluxKernel m_resElementIndex( perforationData->getField< fields::perforation::reservoirElementIndex >()), m_compPerfRate( perforationData->getField< fields::well::compPerforationRate >()), m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate >()), - m_dCompPerfRate_dPres( perforationData->getField< fields::well::dCompPerforationRate_dPres >()), - m_dCompPerfRate_dComp( perforationData->getField< fields::well::dCompPerforationRate_dComp >()), m_disableReservoirToWellFlow( disableReservoirToWellFlow ) - {} + {} -struct StackVariables + struct StackVariables { public: /** @@ -152,45 +148,30 @@ struct StackVariables GEOS_HOST_DEVICE StackVariables() {} - + }; - template< typename STRUCT = NoOpFunc > + template< typename STRUCT = NoOpFunc > GEOS_HOST_DEVICE inline void computeFlux( localIndex const iperf, STRUCT && stack= NoOpFunc{} ) const { - // get the index of the reservoir elem - localIndex const er = m_resElementRegion[iperf]; - localIndex const esr = m_resElementSubRegion[iperf]; - localIndex const ei = m_resElementIndex[iperf]; - - // get the index of the well elem - localIndex const iwelem = m_perfWellElemIndex[iperf]; - + // get the index of the reservoir elem + localIndex const er = m_resElementRegion[iperf]; + localIndex const esr = m_resElementSubRegion[iperf]; + localIndex const ei = m_resElementIndex[iperf]; + + // get the index of the well elem + localIndex const iwelem = m_perfWellElemIndex[iperf]; + using Deriv = multifluid::DerivativeOffset; using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; // local working variables and arrays real64 pres[2]{}; - real64 dPres_dP[2]{}; - real64 dPres_dC[2][NC]{}; - real64 dFlux_dP[2]{}; - real64 dFlux_dC[2][NC]{}; - real64 dMult_dP[2]{}; - real64 dMult_dC[2][NC]{}; - real64 dPotDiff_dP[2]{}; - real64 dPotDiff_dC[2][NC]{}; real64 multiplier[2]{}; - real64 dResTotalMob_dC[NC]{}; - real64 dDens_dC[NC]{}; - real64 dVisc_dC[NC]{}; - real64 dRelPerm_dC[NC]{}; - real64 dMob_dC[NC]{}; - real64 dCompFrac_dCompDens[NC]{}; - // local working variables - compact // All derivative quantiites generated are stored in arrays using CP_Deriv offsets // The input well/reservoir quantites use the Deriv offsets @@ -203,19 +184,6 @@ struct StackVariables real64 dCompFrac[CP_Deriv::nDer]{}; // Step 1: reset the perforation rates - // tjb - remove when safe - for( integer ic = 0; ic < NC; ++ic ) - { - m_compPerfRate[iperf][ic] = 0.0; - for( integer ke = 0; ke < 2; ++ke ) - { - m_dCompPerfRate_dPres[iperf][ke][ic] = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - m_dCompPerfRate_dComp[iperf][ke][ic][jc] = 0.0; - } - } - } for( integer ic = 0; ic < NC; ++ic ) { m_compPerfRate[iperf][ic] = 0.0; @@ -227,7 +195,7 @@ struct StackVariables } } } - if constexpr (IS_THERMAL ) + if constexpr (IS_THERMAL ) { // initialize outputs stack.m_energyPerfFlux[iperf]=0; @@ -244,7 +212,6 @@ struct StackVariables // a) get reservoir variables pres[TAG::RES] = m_resPres[er][esr][ei]; - dPres_dP[TAG::RES] = 1.0; dPres[TAG::RES][CP_Deriv::dP] = 1.0; multiplier[TAG::RES] = 1.0; @@ -257,7 +224,6 @@ struct StackVariables pres[TAG::WELL] = m_wellElemPres[iwelem]; std::cout << "wrpres " << iwelem << " RES " << pres[TAG::RES] << " WELL " << pres[TAG::WELL] << " dp " << pres[TAG::WELL]-pres[TAG::RES]; - dPres_dP[TAG::WELL] = 1.0; dPres[TAG::WELL][CP_Deriv::dP] = 1.0; multiplier[TAG::WELL] = -1.0; @@ -265,32 +231,22 @@ struct StackVariables pres[TAG::WELL] += m_wellElemTotalMassDens[iwelem] * gravD; // Note LHS uses CP_Deriv while RHS uses Deriv !!! - dPres_dP[TAG::WELL] += m_dWellElemTotalMassDens_dPres[iwelem] * gravD; - dPres[TAG::WELL][CP_Deriv::dP] += m_dWellElemTotalMassDens_dPres[iwelem] * gravD; + dPres[TAG::WELL][CP_Deriv::dP] += m_dWellElemTotalMassDens[iwelem][Deriv::dP] * gravD; if constexpr ( IS_THERMAL ) { dPres[TAG::WELL][CP_Deriv::dT] += m_dWellElemTotalMassDens[iwelem][Deriv::dT] * gravD; } for( integer ic = 0; ic < NC; ++ic ) { - dPres_dC[TAG::WELL][ic] += m_dWellElemTotalMassDens_dCompDens[iwelem][ic] * gravD; dPres[TAG::WELL][CP_Deriv::dC+ic] += m_dWellElemTotalMassDens[iwelem][Deriv::dC+ic] * gravD; } - - // Step 3: compute potential difference real64 potDiff = 0.0; for( integer i = 0; i < 2; ++i ) { potDiff += multiplier[i] * m_perfTrans[iperf] * pres[i]; - dPotDiff_dP[i] += multiplier[i] * m_perfTrans[iperf] * dPres_dP[i]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dPotDiff_dC[i][ic] += multiplier[i] * m_perfTrans[iperf] * dPres_dC[i][ic]; - } // LHS & RHS both use CP_Deriv for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) { @@ -312,7 +268,6 @@ struct StackVariables // and sum contributions to each component's perforation rate for( integer ip = 0; ip < NP; ++ip ) { - // skip the rest of the calculation if the phase is absent // or if crossflow is disabled for injectors bool const phaseExists = (m_resPhaseVolFrac[er][esr][ei][ip] > 0); @@ -327,16 +282,11 @@ struct StackVariables real64 const resDens = m_resPhaseDens[er][esr][ei][0][ip]; real64 dDens[CP_Deriv::nDer]{}; - real64 const dResDens_dP = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dP]; dDens[CP_Deriv::dP] = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dP]; if constexpr ( IS_THERMAL ) { dDens[CP_Deriv::dT] = m_dResPhaseDens[er][esr][ei][0][ip][Deriv::dT]; } - applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], - m_dResPhaseDens[er][esr][ei][0][ip], - dDens_dC, - Deriv::dC ); applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], m_dResPhaseDens[er][esr][ei][0][ip], &dDens[CP_Deriv::dC], @@ -344,16 +294,12 @@ struct StackVariables // viscosity real64 const resVisc = m_resPhaseVisc[er][esr][ei][0][ip]; real64 dVisc[CP_Deriv::nDer]{}; - real64 const dResVisc_dP = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; dVisc[CP_Deriv::dP] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; if constexpr ( IS_THERMAL ) { dVisc[CP_Deriv::dT] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dT]; } - applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], - m_dResPhaseVisc[er][esr][ei][0][ip], - dVisc_dC, - Deriv::dC ); + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], m_dResPhaseVisc[er][esr][ei][0][ip], &dVisc[CP_Deriv::dC], @@ -362,11 +308,6 @@ struct StackVariables // relative permeability real64 const resRelPerm = m_resPhaseRelPerm[er][esr][ei][0][ip]; real64 dRelPerm[CP_Deriv::nDer]{}; - real64 dResRelPerm_dP = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] = 0; - } for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dRelPerm[jc]=0; @@ -374,7 +315,6 @@ struct StackVariables for( integer jp = 0; jp < NP; ++jp ) { real64 const dResRelPerm_dS = m_dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0][ip][jp]; - dResRelPerm_dP += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; if constexpr ( IS_THERMAL ) { @@ -382,71 +322,33 @@ struct StackVariables } for( integer jc = 0; jc < NC; ++jc ) { - dRelPerm_dC[jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; } } // compute the reservoir phase mobility, including phase density real64 const resPhaseMob = resDens * resRelPerm / resVisc; - real64 const dResPhaseMob_dPres = dResRelPerm_dP * resDens / resVisc - + resPhaseMob * (dResDens_dP / resDens - dResVisc_dP / resVisc); - for( integer jc = 0; jc < NC; ++jc ) - { - dMob_dC[jc] = dRelPerm_dC[jc] * resDens / resVisc - + resPhaseMob * (dDens_dC[jc] / resDens - dVisc_dC[jc] / resVisc); - } + // Handles all dependencies for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dMob[jc] = dRelPerm[jc] * resDens / resVisc - + resPhaseMob * (dDens[jc] / resDens - dVisc[jc] / resVisc); + + resPhaseMob * (dDens[jc] / resDens - dVisc[jc] / resVisc); } - // compute the phase flux and derivatives using upstream cell mobility flux = resPhaseMob * potDiff; - dFlux_dP[TAG::RES] = dResPhaseMob_dPres * potDiff + resPhaseMob * dPotDiff_dP[TAG::RES]; - dFlux_dP[TAG::WELL] = resPhaseMob * dPotDiff_dP[TAG::WELL]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dFlux_dC[TAG::RES][ic] = dMob_dC[ic] * potDiff + resPhaseMob * dPotDiff_dC[TAG::RES][ic]; - dFlux_dC[TAG::WELL][ic] = resPhaseMob * dPotDiff_dC[TAG::WELL][ic]; - } - // Handles all dependencies for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dFlux[TAG::RES][jc] = dMob[jc] * potDiff + resPhaseMob * dPotDiff[TAG::RES][jc]; dFlux[TAG::WELL][jc] = resPhaseMob * dPotDiff[TAG::WELL][jc]; } - // increment component fluxes - for( integer ic = 0; ic < NC; ++ic ) - { - m_compPerfRate[iperf][ic] += flux * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; - - m_dCompPerfRate_dPres[iperf][TAG::RES][ic] += m_resPhaseCompFrac[er][esr][ei][0][ip][ic] * dFlux_dP[TAG::RES]; - m_dCompPerfRate_dPres[iperf][TAG::RES][ic] += m_dResPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP] * flux; - m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] += m_resPhaseCompFrac[er][esr][ei][0][ip][ic] * dFlux_dP[TAG::WELL]; - - applyChainRule( NC, - m_dResCompFrac_dCompDens[er][esr][ei], - m_dResPhaseCompFrac[er][esr][ei][0][ip][ic], - dCompFrac_dCompDens, - Deriv::dC ); - for( integer jc = 0; jc < NC; ++jc ) - { - m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] += dFlux_dC[TAG::RES][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; - m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] += flux * dCompFrac_dCompDens[jc]; - m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] += dFlux_dC[TAG::WELL][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; - } - } // increment component fluxes for( integer ic = 0; ic < NC; ++ic ) { // Note this needs to be uncommented out - // m_compPerfRate[iperf][ic] += flux * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; + m_compPerfRate[iperf][ic] += flux * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; dCompFrac[CP_Deriv::dP] = m_dResPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP]; if constexpr (IS_THERMAL) { @@ -467,17 +369,17 @@ struct StackVariables } } - if constexpr ( IS_THERMAL ) + if constexpr ( IS_THERMAL ) { real64 const res_enthalpy = stack.m_resPhaseEnthalpy[er][esr][ei][0][ip]; stack.m_energyPerfFlux[iperf] += flux * res_enthalpy; // energy equation derivatives WRT res P & T - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * res_enthalpy + - flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * res_enthalpy + - flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * res_enthalpy + + flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; + stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * res_enthalpy + + flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; // energy equation derivatives WRT well P stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * res_enthalpy; stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * res_enthalpy; @@ -489,32 +391,20 @@ struct StackVariables m_dResCompFrac_dCompDens[er][esr][ei], stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip], dProp_dC, - Deriv::dC ); + Deriv::dC ); for( integer jc = 0; jc < NC; ++jc ) { stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dC+jc] += flux * dProp_dC[jc]; - } + } } } // end resevoir is upstream phase loop - // tjb- remove when safe - for( integer ic = 0; ic < NC; ic++ ) - { - assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) < FLT_EPSILON ); - assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] ) < FLT_EPSILON ); - for( integer jc = 0; jc < NC; ++jc ) - { - assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] ) < FLT_EPSILON ); - assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] ) < FLT_EPSILON ); - } - } } else // ** well is upstream ** { real64 resTotalMob = 0.0; - real64 dResTotalMob_dP = 0.0; // we re-compute here the total mass (when useMass == 1) or molar (when useMass == 0) density real64 wellElemTotalDens = 0; @@ -537,16 +427,12 @@ struct StackVariables // viscosity real64 const resVisc = m_resPhaseVisc[er][esr][ei][0][ip]; real64 dVisc[CP_Deriv::nDer]{}; - real64 const dResVisc_dP = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; dVisc[CP_Deriv::dP] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dP]; if constexpr ( IS_THERMAL ) { dVisc[CP_Deriv::dT] = m_dResPhaseVisc[er][esr][ei][0][ip][Deriv::dT]; } - applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], - m_dResPhaseVisc[er][esr][ei][0][ip], - dVisc_dC, - Deriv::dC ); + applyChainRule( NC, m_dResCompFrac_dCompDens[er][esr][ei], m_dResPhaseVisc[er][esr][ei][0][ip], &dVisc[CP_Deriv::dC], @@ -556,11 +442,6 @@ struct StackVariables // relative permeability real64 const resRelPerm = m_resPhaseRelPerm[er][esr][ei][0][ip]; real64 dRelPerm[CP_Deriv::nDer]{}; - real64 dResRelPerm_dP = 0.0; - for( integer jc = 0; jc < NC; ++jc ) - { - dRelPerm_dC[jc] = 0; - } for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { dRelPerm[jc]=0; @@ -568,7 +449,6 @@ struct StackVariables for( integer jp = 0; jp < NP; ++jp ) { real64 const dResRelPerm_dS = m_dResPhaseRelPerm_dPhaseVolFrac[er][esr][ei][0][ip][jp]; - dResRelPerm_dP += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; dRelPerm[CP_Deriv::dP] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; if constexpr ( IS_THERMAL ) { @@ -576,20 +456,11 @@ struct StackVariables } for( integer jc = 0; jc < NC; ++jc ) { - dRelPerm_dC[jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; dRelPerm[CP_Deriv::dC+jc] += dResRelPerm_dS * m_dResPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; } } // increment total mobility resTotalMob += resRelPerm / resVisc; - - dResTotalMob_dP += ( dResRelPerm_dP * resVisc - resRelPerm * dResVisc_dP ) - / ( resVisc * resVisc ); - for( integer ic = 0; ic < NC; ++ic ) - { - dResTotalMob_dC[ic] += ( dRelPerm_dC[ic] * resVisc - resRelPerm * dVisc_dC[ic] ) - / ( resVisc * resVisc ); - } // Handles all dependencies for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { @@ -601,13 +472,6 @@ struct StackVariables // compute a potdiff multiplier = wellElemTotalDens * resTotalMob // wellElemTotalDens is a mass density if useMass == 1 and a molar density otherwise real64 const mult = wellElemTotalDens * resTotalMob; - dMult_dP[TAG::RES] = wellElemTotalDens * dResTotalMob_dP; - dMult_dP[TAG::WELL] = 0.0; // because totalDens does not depend on pressure - for( integer ic = 0; ic < NC; ++ic ) - { - dMult_dC[TAG::RES][ic] = wellElemTotalDens * dResTotalMob_dC[ic]; - dMult_dC[TAG::WELL][ic] = resTotalMob; - } real64 dMult[2][CP_Deriv::nDer]{}; dMult[TAG::WELL][CP_Deriv::dP] = 0.0; @@ -627,14 +491,6 @@ struct StackVariables // compute the volumetric flux and derivatives using upstream cell mobility flux = mult * potDiff; - dFlux_dP[TAG::RES] = dMult_dP[TAG::RES] * potDiff + mult * dPotDiff_dP[TAG::RES]; - dFlux_dP[TAG::WELL] = dMult_dP[TAG::WELL] * potDiff + mult * dPotDiff_dP[TAG::WELL]; - - for( integer ic = 0; ic < NC; ++ic ) - { - dFlux_dC[TAG::RES][ic] = dMult_dC[TAG::RES][ic] * potDiff + mult * dPotDiff_dC[TAG::RES][ic]; - dFlux_dC[TAG::WELL][ic] = dMult_dC[TAG::WELL][ic] * potDiff + mult * dPotDiff_dC[TAG::WELL][ic]; - } for( integer ic = 0; ic < CP_Deriv::nDer; ++ic ) { @@ -645,20 +501,6 @@ struct StackVariables for( integer ic = 0; ic < NC; ++ic ) { m_compPerfRate[iperf][ic] += m_wellElemCompFrac[iwelem][ic] * flux; - m_dCompPerfRate_dPres[iperf][TAG::RES][ic] = m_wellElemCompFrac[iwelem][ic] * dFlux_dP[TAG::RES]; - m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] = m_wellElemCompFrac[iwelem][ic] * dFlux_dP[TAG::WELL]; - - for( integer jc = 0; jc < NC; ++jc ) - { - m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] += m_wellElemCompFrac[iwelem][ic] * dFlux_dC[TAG::RES][jc]; - m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] += m_wellElemCompFrac[iwelem][ic] * dFlux_dC[TAG::WELL][jc]; - m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] += m_dWellElemCompFrac_dCompDens[iwelem][ic][jc] * flux; - } - } - for( integer ic = 0; ic < NC; ++ic ) - { - // Note this needs to be include below when this code above is removed - // m_compPerfRate[iperf][ic] += m_wellElemCompFrac[iwelem][ic] * flux; for( integer jc = 0; jc < CP_Deriv::nDer; ++jc ) { m_dCompPerfRate[iperf][TAG::RES][ic][jc] = m_wellElemCompFrac[iwelem][ic] * dFlux[TAG::RES][jc]; @@ -681,7 +523,7 @@ struct StackVariables { for( integer ip = 0; ip < NP; ++ip ) { -bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; + bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; if( !phaseExists ) continue; double pflux = stack.m_wellElemPhaseVolFrac[iwelem][ip]*flux; @@ -692,7 +534,7 @@ bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy; stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy; - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dP] + pflux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dP]; stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy @@ -709,7 +551,7 @@ bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; for( integer ic=0; ic 0.0; m_dWellElemCompFrac_dCompDens[iwelem], stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip], dProp_dC, - Deriv::dC ); + Deriv::dC ); for( integer jc = 0; jc < NC; ++jc ) { - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dC+jc] += flux * dProp_dC[jc]; - } - } - } - // tjb- remove when safe - for( integer ic = 0; ic < NC; ic++ ) - { - assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::RES][ic] ) < FLT_EPSILON ); - assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dP] -m_dCompPerfRate_dPres[iperf][TAG::WELL][ic] ) < FLT_EPSILON ); - for( integer jc = 0; jc < NC; ++jc ) - { - assert( fabs( m_dCompPerfRate[iperf][TAG::RES][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::RES][ic][jc] ) < FLT_EPSILON ); - assert( fabs( m_dCompPerfRate[iperf][TAG::WELL][ic][CP_Deriv::dC+jc] -m_dCompPerfRate_dComp[iperf][TAG::WELL][ic][jc] ) < FLT_EPSILON ); + stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dC+jc] += pflux * dProp_dC[jc]; + } } } //compFluxKernelOp(er, esr, ei, potDiff, potGrad, flux, dFlux); @@ -756,12 +587,12 @@ bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; { kernelComponent.computeFlux( iperf, kernelComponent.m_stackVariables ); - + } ); } -StackVariables m_stackVariables; + StackVariables m_stackVariables; protected: ElementViewConst< arrayView1d< real64 const > > const m_resPres; @@ -781,8 +612,6 @@ StackVariables m_stackVariables; arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompDens; arrayView1d< real64 const > const m_wellElemTotalMassDens; arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens; - arrayView1d< real64 const > const m_dWellElemTotalMassDens_dPres; - arrayView2d< real64 const, compflow::USD_FLUID_DC > const m_dWellElemTotalMassDens_dCompDens; arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompFrac; arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dWellElemCompFrac_dCompDens; arrayView1d< real64 const > const m_perfGravCoef; @@ -832,23 +661,19 @@ class PerforationFluxKernelFactory integer const disableReservoirToWellFlow ) { geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases, [&]( auto NC, auto NP ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_PHASE = NP(); - integer constexpr IS_THERMAL = 0; - - using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); - //typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, flowSolverName ); + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_PHASE = NP(); + integer constexpr IS_THERMAL = 0; + + using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); typename kernelType::RelPermAccessors relPermAccessors( elemManager, flowSolverName ); - //ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - // elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - //dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - kernelType kernel( perforationData, subRegion, compFlowAccessors, multiFluidAccessors, relPermAccessors, disableReservoirToWellFlow ); - kernelType::template launch< POLICY >( perforationData->size(), kernel ); - } ); + kernelType kernel( perforationData, subRegion, compFlowAccessors, multiFluidAccessors, relPermAccessors, disableReservoirToWellFlow ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); } }; @@ -880,7 +705,7 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati /// Compile time value for thermal option static constexpr integer isThermal = IS_THERMAL; - + using TAG = typename Base::TAG; using CompFlowAccessors = typename Base::CompFlowAccessors; using MultiFluidAccessors = typename Base::MultiFluidAccessors; @@ -919,26 +744,18 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati ThermalCompFlowAccessors const & thermalCompFlowAccessors, ThermalMultiFluidAccessors const & thermalMultiFluidAccessors ) : Base( perforationData, - subRegion, - compFlowAccessors, - multiFluidAccessors, - relPermAccessors, - disableReservoirToWellFlow ), + subRegion, + compFlowAccessors, + multiFluidAccessors, + relPermAccessors, + disableReservoirToWellFlow ), m_stack( subRegion, - perforationData, - fluid, - thermalCompFlowAccessors, + perforationData, + fluid, + thermalCompFlowAccessors, thermalMultiFluidAccessors ) - - //m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), - //m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), - // m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()) , - //m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) , - //m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), - //m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), - //m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) - {} + {} struct StackVariables : public Base::StackVariables @@ -960,28 +777,28 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()), m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), - m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) + m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) {} - /// Views on well element properties - arrayView2d< real64 const, compflow::USD_PHASE > m_wellElemPhaseVolFrac; - arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; - arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; - - /// Views on energy flux - arrayView1d< real64 > const & m_energyPerfFlux; - arrayView3d< real64 > const & m_dEnergyPerfFlux; - - /// Views on temperature + /// Views on well element properties + arrayView2d< real64 const, compflow::USD_PHASE > m_wellElemPhaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; + arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; + + /// Views on energy flux + arrayView1d< real64 > const & m_energyPerfFlux; + arrayView3d< real64 > const & m_dEnergyPerfFlux; + + /// Views on temperature ElementViewConst< arrayView1d< real64 const > > const m_temp; - /// Views on phase enthalpies + /// Views on phase enthalpies ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseEnthalpy; ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseEnthalpy; }; - template< typename FUNC = NoOpFunc > + template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE inline void @@ -990,8 +807,8 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati Base::computeFlux( iperf, m_stack ); } - - + + /** * @brief Performs the kernel launch * @tparam POLICY the policy used in the RAJA kernels @@ -1009,7 +826,7 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati { //kernelComponent.setupStack(iperf); kernelComponent.computeFlux( iperf ); - + } ); } @@ -1017,7 +834,7 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati /// Stack continaining thermal variables StackVariables m_stack; - + }; @@ -1053,29 +870,24 @@ class PerforationFluxKernelFactory integer const disableReservoirToWellFlow ) { geos::internal::kernelLaunchSelectorCompPhaseSwitch( numComp, numPhases, [&]( auto NC, auto NP ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_PHASE = NP(); - integer constexpr IS_THERMAL = 1; - - using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); - //typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, flowSolverName ); + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_PHASE = NP(); + integer constexpr IS_THERMAL = 1; + + using kernelType = PerforationFluxKernel< NUM_COMP, NUM_PHASE, IS_THERMAL >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, flowSolverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, flowSolverName ); typename kernelType::RelPermAccessors relPermAccessors( elemManager, flowSolverName ); typename kernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, flowSolverName ); typename kernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, flowSolverName ); - //typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, flowSolverName ); - //ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - // elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - //dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - kernelType kernel( perforationData, subRegion, fluid, compFlowAccessors, multiFluidAccessors, - relPermAccessors, disableReservoirToWellFlow, - thermalCompFlowAccessors, - thermalMultiFluidAccessors ); - kernelType::template launch< POLICY >( perforationData->size(), kernel ); - } ); + + kernelType kernel( perforationData, subRegion, fluid, compFlowAccessors, multiFluidAccessors, + relPermAccessors, disableReservoirToWellFlow, + thermalCompFlowAccessors, + thermalMultiFluidAccessors ); + kernelType::template launch< POLICY >( perforationData->size(), kernel ); + } ); } }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 1e634bbf1ba..665c2d69114 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -51,7 +51,7 @@ SinglePhaseWell::SinglePhaseWell( const string & name, { m_numDofPerWellElement = 2; m_numDofPerResElement = 1; -m_numPhases = 1; + m_numPhases = 1; m_numComponents = 1; } @@ -89,13 +89,13 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) WellControls & wellControls = getWellControls( subRegion ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() ); -wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). setSizedFromParent( 0 ). reference().resizeDimension< 0 >( 2 ); // dP, dT wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentBHP_dPresString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentVolRateString() ); -wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentVolRateString() ). + wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentVolRateString() ). setSizedFromParent( 0 ). reference().resizeDimension< 0 >( 3 ); // dP, dT, dQ @@ -198,7 +198,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const & dens = fluid.density(); arrayView2d< real64 const > const & dDens_dPres = fluid.dDensity_dPressure(); -arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); + arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); // control data WellControls & wellControls = getWellControls( subRegion ); @@ -208,7 +208,7 @@ arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); real64 & currentBHP = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ); -arrayView1d< real64 > const & dCurrentBHP = + arrayView1d< real64 > const & dCurrentBHP = wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentBHPString() ); real64 & dCurrentBHP_dPres = @@ -220,20 +220,20 @@ arrayView1d< real64 > const & dCurrentBHP = //using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >; using Deriv = multifluid::DerivativeOffset; forAll< serialPolicy >( 1, [ pres, - dens, - dDens_dPres, -dDens_dTemp, - wellElemGravCoef, - ¤tBHP, -&dCurrentBHP, - &dCurrentBHP_dPres, - &iwelemRef, - &refGravCoef] ( localIndex const ) - { - real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; + dens, + dDens_dPres, + dDens_dTemp, + wellElemGravCoef, + ¤tBHP, + &dCurrentBHP, + &dCurrentBHP_dPres, + &iwelemRef, + &refGravCoef] ( localIndex const ) + { + real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * diffGravCoef; dCurrentBHP[Deriv::dP] = 1.0 + dDens_dPres[iwelemRef][0] * diffGravCoef; - dCurrentBHP_dPres = 1.0 + dDens_dPres[iwelemRef][0] * diffGravCoef; + dCurrentBHP_dPres = 1.0 + dDens_dPres[iwelemRef][0] * diffGravCoef; if constexpr ( IS_THERMAL ) { @@ -274,7 +274,7 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const & dens = fluid.density(); arrayView2d< real64 const > const & dDens_dPres = fluid.dDensity_dPressure(); -arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); + arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); // control data WellControls & wellControls = getWellControls( subRegion ); @@ -285,7 +285,7 @@ arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); real64 & currentVolRate = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() ); -arrayView1d< real64 > const & dCurrentVolRate = + arrayView1d< real64 > const & dCurrentVolRate = wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentVolRateString() ); real64 & dCurrentVolRate_dPres = @@ -296,70 +296,70 @@ arrayView1d< real64 > const & dCurrentVolRate = constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); -geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL ) { + geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL ) { integer constexpr IS_THERMAL = ISTHERMAL(); using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >; - // bring everything back to host, capture the scalars by reference - forAll< serialPolicy >( 1, [fluidWrapper, - pres, - connRate, - dens, - dDens_dPres, -dDens_dTemp, - &useSurfaceConditions, - &surfacePres, - ¤tVolRate, -&dCurrentVolRate, - &dCurrentVolRate_dPres, - &dCurrentVolRate_dRate, - &iwelemRef, - &logLevel, - &wellControlsName] ( localIndex const ) - { - // We need to evaluate the density as follows: - // - Surface conditions: using the surface pressure provided by the user - // - Reservoir conditions: using the pressure in the top element - - if( useSurfaceConditions ) + // bring everything back to host, capture the scalars by reference + forAll< serialPolicy >( 1, [fluidWrapper, + pres, + connRate, + dens, + dDens_dPres, + dDens_dTemp, + &useSurfaceConditions, + &surfacePres, + ¤tVolRate, + &dCurrentVolRate, + &dCurrentVolRate_dPres, + &dCurrentVolRate_dRate, + &iwelemRef, + &logLevel, + &wellControlsName] ( localIndex const ) { - // we need to compute the surface density - fluidWrapper.update( iwelemRef, 0, surfacePres ); - if( logLevel >= 2 ) + // We need to evaluate the density as follows: + // - Surface conditions: using the surface pressure provided by the user + // - Reservoir conditions: using the pressure in the top element + + if( useSurfaceConditions ) { - GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa", - wellControlsName, surfacePres ) ); + // we need to compute the surface density + fluidWrapper.update( iwelemRef, 0, surfacePres ); + if( logLevel >= 2 ) + { + GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa", + wellControlsName, surfacePres ) ); #ifdef GEOS_USE_HIP - GEOS_UNUSED_VAR( wellControlsName ); + GEOS_UNUSED_VAR( wellControlsName ); #endif + } + } + else + { + real64 const refPres = pres[iwelemRef]; + fluidWrapper.update( iwelemRef, 0, refPres ); } - } - else - { - real64 const refPres = pres[iwelemRef]; - fluidWrapper.update( iwelemRef, 0, refPres ); - } - real64 const densInv = 1.0 / dens[iwelemRef][0]; - currentVolRate = connRate[iwelemRef] * densInv; - dCurrentVolRate_dPres = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; -dCurrentVolRate[COFFSET_WJ::dP] = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; - dCurrentVolRate_dRate = densInv; -dCurrentVolRate[COFFSET_WJ::dQ] = densInv; + real64 const densInv = 1.0 / dens[iwelemRef][0]; + currentVolRate = connRate[iwelemRef] * densInv; + dCurrentVolRate_dPres = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; + dCurrentVolRate[COFFSET_WJ::dP] = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; + dCurrentVolRate_dRate = densInv; + dCurrentVolRate[COFFSET_WJ::dQ] = densInv; if constexpr ( IS_THERMAL ) { dCurrentVolRate[COFFSET_WJ::dT] = -( useSurfaceConditions == 0 ) * dDens_dTemp[iwelemRef][0] * currentVolRate * densInv; } - if( logLevel >= 2 && useSurfaceConditions ) - { - GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} kg/sm3. \n" - "The total rate is {} kg/s, which corresponds to a total surface volumetric rate of {} sm3/s", - wellControlsName, dens[iwelemRef][0], - connRate[iwelemRef], currentVolRate ) ); - } + if( logLevel >= 2 && useSurfaceConditions ) + { + GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} kg/sm3. \n" + "The total rate is {} kg/s, which corresponds to a total surface volumetric rate of {} sm3/s", + wellControlsName, dens[iwelemRef][0], + connRate[iwelemRef], currentVolRate ) ); + } + } ); } ); } ); -} ); } void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const @@ -413,77 +413,102 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & if( time_n <= 0.0 || ( !wellControls.isWellOpen( time_n ) && wellControls.isWellOpen( time_n + dt ) ) ) { - PerforationData const & perforationData = *subRegion.getPerforationData(); + PerforationData const & perforationData = *subRegion.getPerforationData(); + + // get the info stored on well elements + arrayView1d< real64 const > const wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); + + // get well primary variables on well elements + arrayView1d< real64 > const wellElemPressure = + subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 > const connRate = + subRegion.getField< fields::well::connectionRate >(); + + // get the element region, subregion, index + arrayView1d< localIndex const > const resElementRegion = + perforationData.getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const resElementSubRegion = + perforationData.getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const resElementIndex = + perforationData.getField< fields::perforation::reservoirElementIndex >(); + + arrayView1d< real64 const > const & perfGravCoef = + perforationData.getField< fields::well::gravityCoefficient >(); + + // TODO: change the way we access the flowSolver here + SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() ); + PresInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( meshLevel.getElemManager(), flowSolver.getName() ); + PresInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( meshLevel.getElemManager(), flowSolver.getName() ); + + // 1) Loop over all perforations to compute an average density + // 2) Initialize the reference pressure + // 3) Estimate the pressures in the well elements using the average density + PresInitializationKernel:: + launch( perforationData.size(), + subRegion.size(), + perforationData.getNumPerforationsGlobal(), + wellControls, + 0.0, // initialization done at t = 0 + resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), + resSingleFluidAccessors.get( fields::singlefluid::density{} ), + resElementRegion, + resElementSubRegion, + resElementIndex, + perfGravCoef, + wellElemGravCoef, + wellElemPressure ); + + // 4) Recompute the pressure-dependent properties + // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState) + // to better initialize the rates + updateSubRegionState( subRegion ); + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); + arrayView2d< real64 const > const & wellElemDens = fluid.density(); + + // 5) Estimate the well rates + RateInitializationKernel::launch( subRegion.size(), + wellControls, + 0.0, // initialization done at t = 0 + wellElemDens, + connRate ); + } - // get the info stored on well elements - arrayView1d< real64 const > const wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); + } ); - // get well primary variables on well elements - arrayView1d< real64 > const wellElemPressure = - subRegion.getField< fields::well::pressure >(); - arrayView1d< real64 > const connRate = - subRegion.getField< fields::well::connectionRate >(); + } ); +} - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = - perforationData.getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = - perforationData.getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = - perforationData.getField< fields::perforation::reservoirElementIndex >(); - - arrayView1d< real64 const > const & perfGravCoef = - perforationData.getField< fields::well::gravityCoefficient >(); - - // TODO: change the way we access the flowSolver here - SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() ); - PresInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( meshLevel.getElemManager(), flowSolver.getName() ); - PresInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( meshLevel.getElemManager(), flowSolver.getName() ); - - // 1) Loop over all perforations to compute an average density - // 2) Initialize the reference pressure - // 3) Estimate the pressures in the well elements using the average density - PresInitializationKernel:: - launch( perforationData.size(), - subRegion.size(), - perforationData.getNumPerforationsGlobal(), - wellControls, - 0.0, // initialization done at t = 0 - resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), - resSingleFluidAccessors.get( fields::singlefluid::density{} ), - resElementRegion, - resElementSubRegion, - resElementIndex, - perfGravCoef, - wellElemGravCoef, - wellElemPressure ); - - // 4) Recompute the pressure-dependent properties - // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState) - // to better initialize the rates - updateSubRegionState( subRegion ); +void SinglePhaseWell::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + GEOS_MARK_FUNCTION; + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); - arrayView2d< real64 const > const & wellElemDens = fluid.density(); - - // 5) Estimate the well rates - RateInitializationKernel::launch( subRegion.size(), - wellControls, - 0.0, // initialization done at t = 0 - wellElemDens, - connRate ); - } + // then assemble the pressure relations between well elements + assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - } ); + // then compute the perforation rates (later assembled by the coupled solver) + computePerforationRates( time, dt, domain ); - } ); + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); + + + // then apply a special treatment to the wells that are shut + //shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); } void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, real64 const & dt, - DomainPartition & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -507,25 +532,25 @@ void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, if( wellControls.isWellOpen( time_n + dt ) ) { - // get a reference to the degree-of-freedom numbers - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); - - // get a reference to the primary variables on well elements - arrayView1d< real64 const > const connRate = - subRegion.getField< fields::well::connectionRate >(); - - FluxKernel::launch( subRegion.size(), - dofManager.rankOffset(), - wellElemDofNumber, - nextWellElemIndex, - connRate, - dt, - localMatrix, - localRhs ); + // get a reference to the degree-of-freedom numbers + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< localIndex const > const & nextWellElemIndex = + subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); + + // get a reference to the primary variables on well elements + arrayView1d< real64 const > const connRate = + subRegion.getField< fields::well::connectionRate >(); + + FluxKernel::launch( subRegion.size(), + dofManager.rankOffset(), + wellElemDofNumber, + nextWellElemIndex, + connRate, + dt, + localMatrix, + localRhs ); } } ); @@ -559,75 +584,75 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, if( wellControls.isWellOpen( time_n + dt ) ) { - // get the degrees of freedom numbers, depth, next well elem index - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< real64 const > const & wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); - - // get primary variables on well elements - arrayView1d< real64 const > const & wellElemPressure = - subRegion.getField< fields::well::pressure >(); - - // get well constitutive data - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); - arrayView2d< real64 const > const & wellElemDensity = fluid.density(); - arrayView2d< real64 const > const & dWellElemDensity_dPres = fluid.dDensity_dPressure(); - - localIndex const controlHasSwitched = - PressureRelationKernel::launch( subRegion.size(), - dofManager.rankOffset(), - subRegion.isLocallyOwned(), - subRegion.getTopWellElementIndex(), - wellControls, - time_n + dt, // controls evaluated with BHP/rate of the end of the time interval - wellElemDofNumber, - wellElemGravCoef, - nextWellElemIndex, - wellElemPressure, - wellElemDensity, - dWellElemDensity_dPres, - localMatrix, - localRhs ); - - if( controlHasSwitched == 1 ) - { - // Note: if BHP control is not viable, we switch to TOTALVOLRATE - // if TOTALVOLRATE is not viable, we switch to BHP + // get the degrees of freedom numbers, depth, next well elem index + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< real64 const > const & wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); + arrayView1d< localIndex const > const & nextWellElemIndex = + subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); + + // get primary variables on well elements + arrayView1d< real64 const > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + + // get well constitutive data + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); + arrayView2d< real64 const > const & wellElemDensity = fluid.density(); + arrayView2d< real64 const > const & dWellElemDensity_dPres = fluid.dDensity_dPressure(); + + localIndex const controlHasSwitched = + PressureRelationKernel::launch( subRegion.size(), + dofManager.rankOffset(), + subRegion.isLocallyOwned(), + subRegion.getTopWellElementIndex(), + wellControls, + time_n + dt, // controls evaluated with BHP/rate of the end of the time interval + wellElemDofNumber, + wellElemGravCoef, + nextWellElemIndex, + wellElemPressure, + wellElemDensity, + dWellElemDensity_dPres, + localMatrix, + localRhs ); + + if( controlHasSwitched == 1 ) + { + // Note: if BHP control is not viable, we switch to TOTALVOLRATE + // if TOTALVOLRATE is not viable, we switch to BHP - real64 const timeAtEndOfStep = time_n + dt; + real64 const timeAtEndOfStep = time_n + dt; - if( wellControls.getControl() == WellControls::Control::BHP ) - { - wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from BHP constraint to rate constraint" ); - } - else - { - wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from rate constraint to BHP constraint" ); + if( wellControls.getControl() == WellControls::Control::BHP ) + { + wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() + << " from BHP constraint to rate constraint" ); + } + else + { + wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() + << " from rate constraint to BHP constraint" ); + } } } - } } ); } ); } void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, - real64 const & dt, DomainPartition const & domain, + real64 const & dt, DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; -if( 0 ) + if( 0 ) { string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -674,46 +699,46 @@ if( 0 ) } else { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { - ElementRegionManager const & elemManager = mesh.getElemManager(); + ElementRegionManager const & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion const & subRegion ) + { - // get a reference to the degree-of-freedom numbers - string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellElemDofKey ); - arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank(); + // get a reference to the degree-of-freedom numbers + string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellElemDofKey ); + arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank(); WellControls & wellControls = getWellControls( subRegion ); if( wellControls.isWellOpen( time_n + dt ) ) { - arrayView1d< real64 const > const wellElemVolume = subRegion.getElementVolume(); - - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); - arrayView2d< real64 const > const wellElemDensity = fluid.density(); - arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); - arrayView2d< real64 const > const wellElemDensity_n = fluid.density_n(); - - AccumulationKernel::launch( subRegion.size(), - dofManager.rankOffset(), - wellElemDofNumber, - wellElemGhostRank, - wellElemVolume, - wellElemDensity, - dWellElemDensity_dPres, - wellElemDensity_n, - localMatrix, - localRhs ); + arrayView1d< real64 const > const wellElemVolume = subRegion.getElementVolume(); + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); + arrayView2d< real64 const > const wellElemDensity = fluid.density(); + arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); + arrayView2d< real64 const > const wellElemDensity_n = fluid.density_n(); + + AccumulationKernel::launch( subRegion.size(), + dofManager.rankOffset(), + wellElemDofNumber, + wellElemGhostRank, + wellElemVolume, + wellElemDensity, + dWellElemDensity_dPres, + wellElemDensity_n, + localMatrix, + localRhs ); } else { @@ -743,19 +768,9 @@ if( 0 ) } + } ); } ); - } ); -} -} - - void SinglePhaseWell::assembleVolumeBalanceTerms( real64 const & GEOS_UNUSED_PARAM( time_n ), - real64 const & GEOS_UNUSED_PARAM( dt ), - DomainPartition const & GEOS_UNUSED_PARAM( domain ), - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), - arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) -{ - // not implemented for single phase flow + } } void SinglePhaseWell::shutDownWell( real64 const time_n, @@ -835,8 +850,8 @@ void SinglePhaseWell::shutDownWell( real64 const time_n, } - void SinglePhaseWell::computePerforationRates( real64 const & time_n, - real64 const & dt, DomainPartition & domain ) +void SinglePhaseWell::computePerforationRates( real64 const & time_n, + real64 const & dt, DomainPartition & domain ) { GEOS_MARK_FUNCTION; @@ -854,70 +869,70 @@ void SinglePhaseWell::shutDownWell( real64 const time_n, WellElementSubRegion & subRegion ) { - WellControls const & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time_n + dt ) ) - { - - // get the well data - PerforationData * const perforationData = subRegion.getPerforationData(); - - // get the degrees of freedom and depth - arrayView1d< real64 const > const wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); - - // get well primary variables on well elements - arrayView1d< real64 const > const wellElemPressure = - subRegion.getField< fields::well::pressure >(); + WellControls const & wellControls = getWellControls( subRegion ); + if( wellControls.isWellOpen( time_n + dt ) ) + { - // get well constitutive data - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const wellElemDensity = fluid.density(); - arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); - arrayView2d< real64 const > const wellElemViscosity = fluid.viscosity(); - arrayView2d< real64 const > const dWellElemViscosity_dPres = fluid.dViscosity_dPressure(); - - // get well variables on perforations - arrayView1d< real64 const > const perfGravCoef = - perforationData->getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - arrayView1d< real64 const > const perfTransmissibility = - perforationData->getField< fields::perforation::wellTransmissibility >(); - - arrayView1d< real64 > const perfRate = - perforationData->getField< fields::well::perforationRate >(); - arrayView2d< real64 > const dPerfRate_dPres = - perforationData->getField< fields::well::dPerforationRate_dPres >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - PerforationKernel::launch( perforationData->size(), - resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), - resSingleFluidAccessors.get( fields::singlefluid::density{} ), - resSingleFluidAccessors.get( fields::singlefluid::dDensity_dPressure{} ), - resSingleFluidAccessors.get( fields::singlefluid::viscosity{} ), - resSingleFluidAccessors.get( fields::singlefluid::dViscosity_dPressure{} ), - wellElemGravCoef, - wellElemPressure, - wellElemDensity, - dWellElemDensity_dPres, - wellElemViscosity, - dWellElemViscosity_dPres, - perfGravCoef, - perfWellElemIndex, - perfTransmissibility, - resElementRegion, - resElementSubRegion, - resElementIndex, - perfRate, - dPerfRate_dPres ); - } + // get the well data + PerforationData * const perforationData = subRegion.getPerforationData(); + + // get the degrees of freedom and depth + arrayView1d< real64 const > const wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); + + // get well primary variables on well elements + arrayView1d< real64 const > const wellElemPressure = + subRegion.getField< fields::well::pressure >(); + + // get well constitutive data + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const wellElemDensity = fluid.density(); + arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); + arrayView2d< real64 const > const wellElemViscosity = fluid.viscosity(); + arrayView2d< real64 const > const dWellElemViscosity_dPres = fluid.dViscosity_dPressure(); + + // get well variables on perforations + arrayView1d< real64 const > const perfGravCoef = + perforationData->getField< fields::well::gravityCoefficient >(); + arrayView1d< localIndex const > const perfWellElemIndex = + perforationData->getField< fields::perforation::wellElementIndex >(); + arrayView1d< real64 const > const perfTransmissibility = + perforationData->getField< fields::perforation::wellTransmissibility >(); + + arrayView1d< real64 > const perfRate = + perforationData->getField< fields::well::perforationRate >(); + arrayView2d< real64 > const dPerfRate_dPres = + perforationData->getField< fields::well::dPerforationRate_dPres >(); + + // get the element region, subregion, index + arrayView1d< localIndex const > const resElementRegion = + perforationData->getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const resElementSubRegion = + perforationData->getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const resElementIndex = + perforationData->getField< fields::perforation::reservoirElementIndex >(); + + PerforationKernel::launch( perforationData->size(), + resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), + resSingleFluidAccessors.get( fields::singlefluid::density{} ), + resSingleFluidAccessors.get( fields::singlefluid::dDensity_dPressure{} ), + resSingleFluidAccessors.get( fields::singlefluid::viscosity{} ), + resSingleFluidAccessors.get( fields::singlefluid::dViscosity_dPressure{} ), + wellElemGravCoef, + wellElemPressure, + wellElemDensity, + dWellElemDensity_dPres, + wellElemViscosity, + dWellElemViscosity_dPres, + perfGravCoef, + perfWellElemIndex, + perfTransmissibility, + resElementRegion, + resElementSubRegion, + resElementIndex, + perfRate, + dPerfRate_dPres ); + } } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index fdb03ce6673..2d41dbd9bc3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -168,6 +168,12 @@ class SinglePhaseWell : public WellSolverBase */ virtual void updateSubRegionState( WellElementSubRegion & subRegion ) override; + virtual void assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the flux terms for all connections between well elements * @param time_n previous time value @@ -179,7 +185,7 @@ class SinglePhaseWell : public WellSolverBase */ void assembleFluxTerms( real64 const & time_n, real64 const & dt, - DomainPartition & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; @@ -192,23 +198,11 @@ class SinglePhaseWell : public WellSolverBase * @param rhs the system right-hand side vector */ void assembleAccumulationTerms( real64 const & time_n, - real64 const & dt, DomainPartition const & domain, + real64 const & dt, DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - /** - * @brief assembles the volume balance terms for all well elements - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void assembleVolumeBalanceTerms( real64 const & time_n, - real64 const & dt, DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the pressure relations at all connections between well elements except at the well head @@ -249,11 +243,11 @@ class SinglePhaseWell : public WellSolverBase // control data (not registered on the mesh) static constexpr char const * currentBHPString() { return "currentBHP"; } -static constexpr char const * dCurrentBHPString() { return "dCurrentBHP"; } + static constexpr char const * dCurrentBHPString() { return "dCurrentBHP"; } static constexpr char const * dCurrentBHP_dPresString() { return "dCurrentBHP_dPres"; } static constexpr char const * currentVolRateString() { return "currentVolumetricRate"; } -static constexpr char const * dCurrentVolRateString() { return "dCurrentVolumetricRate"; } + static constexpr char const * dCurrentVolRateString() { return "dCurrentVolumetricRate"; } static constexpr char const * dCurrentVolRate_dPresString() { return "dCurrentVolumetricRate_dPres"; } static constexpr char const * dCurrentVolRate_dRateString() { return "dCurrentVolumetricRate_dRate"; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 5bb7aa04167..dc56557a1c3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -46,8 +46,6 @@ class TotalMassDensityKernel : public compositionalMultiphaseWellKernels::TotalM using Base::m_dPhaseMassDens; using Base::m_dPhaseVolFrac; using Base::m_dTotalMassDens; - using Base::m_dTotalMassDens_dCompDens; - using Base::m_dTotalMassDens_dPres; using Base::m_phaseMassDens; using Base::m_phaseVolFrac; using Base::m_totalMassDens; @@ -61,8 +59,7 @@ class TotalMassDensityKernel : public compositionalMultiphaseWellKernels::TotalM */ TotalMassDensityKernel( ObjectManagerBase & subRegion, MultiFluidBase const & fluid ) - : Base( subRegion, fluid ), - m_dTotalMassDens_dTemp( subRegion.getField< fields::well::dTotalMassDensity_dTemperature >()) + : Base( subRegion, fluid ) {} /** @@ -80,13 +77,11 @@ class TotalMassDensityKernel : public compositionalMultiphaseWellKernels::TotalM arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseMassDens = m_phaseMassDens[ei][0]; arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseMassDens = m_dPhaseMassDens[ei][0]; - real64 & dTotalMassDens_dTemp = m_dTotalMassDens_dTemp[ei]; real64 & dTotalMassDens_dT = m_dTotalMassDens[ei][Deriv::dT]; // Call the base compute the compute the total mass density and derivatives return Base::compute( ei, [&]( localIndex const ip ) { - dTotalMassDens_dTemp += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; dTotalMassDens_dT += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT]; } ); } @@ -652,7 +647,7 @@ class ElementBasedAssemblyKernelFactory internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { localIndex constexpr NUM_COMP = NC(); - + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) @@ -668,15 +663,15 @@ class ElementBasedAssemblyKernelFactory /** * @class FaceBasedAssemblyKernel * @tparam NUM_COMP number of fluid components - * @brief Define the interface for the assembly kernel in charge of flux terms + * @brief Define the interface for the assembly kernel in charge of flux terms */ template< integer NC > class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, 1 > { public: -static constexpr integer IS_THERMAL = 1; + static constexpr integer IS_THERMAL = 1; using Base = compositionalMultiphaseWellKernels::FaceBasedAssemblyKernel< NC, IS_THERMAL >; - + // Well jacobian column and row indicies using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; @@ -723,18 +718,18 @@ static constexpr integer IS_THERMAL = 1; string const wellDofKey, WellControls const & wellControls, ElementSubRegionBase const & subRegion, -MultiFluidBase const & fluid, + MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) : Base( dt , rankOffset , wellDofKey - , wellControls - , subRegion - , localMatrix - , localRhs - , kernelFlags ), + , wellControls + , subRegion + , localMatrix + , localRhs + , kernelFlags ), m_numPhases ( fluid.numFluidPhases()), m_phaseFraction( fluid.phaseFraction()), m_dPhaseFraction( fluid.dPhaseFraction()), @@ -742,12 +737,12 @@ MultiFluidBase const & fluid, m_dPhaseEnthalpy( fluid.dPhaseEnthalpy()) { } -struct StackVariables : public Base::StackVariables + struct StackVariables : public Base::StackVariables { public: - GEOS_HOST_DEVICE - StackVariables( localIndex const size ) + GEOS_HOST_DEVICE + StackVariables( localIndex const size ) : Base::StackVariables( size ) {} @@ -893,7 +888,7 @@ struct StackVariables : public Base::StackVariables * @param[inout] stack the stack variables * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes */ - + GEOS_HOST_DEVICE inline void computeFlux( localIndex const iwelem, StackVariables & stack ) const @@ -904,9 +899,9 @@ struct StackVariables : public Base::StackVariables , real64 const (&dCompFrac_dCompDens)[NC][NC] ) { - if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector - { - real64 eflux=0; + if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector + { + real64 eflux=0; real64 eflux_dq=0; for( integer ip = 0; ip < m_numPhases; ++ip ) { @@ -932,7 +927,7 @@ struct StackVariables : public Base::StackVariables { stack.localEnergyFluxJacobian[0] [dof] *= -m_dt*currentConnRate; } - // Energy equation + // Energy equation stack.localEnergyFlux[0] = -m_dt * eflux * currentConnRate; stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt * eflux_dq; } @@ -942,7 +937,7 @@ struct StackVariables : public Base::StackVariables real64 eflux_dq=0; for( integer ip = 0; ip < m_numPhases; ++ip ) { - eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; stack.localEnergyFluxJacobian[0] [CP_Deriv::dP] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP] + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dP]*m_phaseFraction[iwelemUp][0][ip]; @@ -959,7 +954,7 @@ struct StackVariables : public Base::StackVariables + dProp1_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; } - } + } for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { @@ -974,7 +969,7 @@ struct StackVariables : public Base::StackVariables real64 eflux_dq=0; for( integer ip = 0; ip < m_numPhases; ++ip ) { - eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; + eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip]; eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip]; real64 dprop_dp = m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP] @@ -1011,7 +1006,7 @@ struct StackVariables : public Base::StackVariables stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] *= -m_dt*currentConnRate; } } - + } ); } @@ -1059,7 +1054,7 @@ struct StackVariables : public Base::StackVariables /** * @class FaceBasedAssemblyKernelFactory */ -class FaceBasedAssemblyKernelFactory +class FaceBasedAssemblyKernelFactory { public: @@ -1085,14 +1080,14 @@ class FaceBasedAssemblyKernelFactory string const dofKey, WellControls const & wellControls, ElementSubRegionBase const & subRegion, -MultiFluidBase const & fluid, + MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { integer constexpr NUM_COMP = NC(); - + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; if( useTotalMassEquation ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp index 3c7be63183f..c55a1f2991e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp @@ -95,7 +95,7 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs * @struct StackVariables * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack */ - struct StackVariables : public Base::StackVariables + struct StackVariables : public Base::StackVariables { public: GEOS_HOST_DEVICE @@ -111,7 +111,7 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs using Base::StackVariables::density; using Base::StackVariables::density_n; using Base::StackVariables::dDensity_dPres; - + }; /** * @brief Getter for the ghost rank of an element @@ -123,7 +123,7 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs { return m_elemGhostRank( ei ); } - + /** * @brief Compute the local accumulation contributions to the residual and Jacobian * @tparam FUNC the type of the function that can be used to customize the kernel @@ -157,13 +157,13 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs stack.localResidual[numEqn-1] = fluidEnergy - fluidEnergy_n; // derivatives w.r.t. pressure and temperature - stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; + stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; stack.localJacobian[numEqn-1][numDof-1] = dFluidEnergy_dT; - } ); + } ); } - + /** * @brief Performs the kernel launch * @tparam POLICY the policy used in the RAJA kernels @@ -202,7 +202,7 @@ class ElementBasedAssemblyKernel : public singlePhaseWellKernels::ElementBasedAs arrayView2d< real64 const > const m_internalEnergy_n; arrayView2d< real64 const > const m_dInternalEnergy_dPres; arrayView2d< real64 const > const m_dInternalEnergy_dTemp; - + }; @@ -231,12 +231,12 @@ class ElementBasedAssemblyKernelFactory CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - integer constexpr NUM_DOF = 2; + integer constexpr NUM_DOF = 2; ElementBasedAssemblyKernel< NUM_DOF > - kernel( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ); - ElementBasedAssemblyKernel< NUM_DOF >::template + kernel( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ); + ElementBasedAssemblyKernel< NUM_DOF >::template launch< POLICY, ElementBasedAssemblyKernel< NUM_DOF > >( subRegion.size(), kernel ); - + } }; } // end namespace singlePhaseWellKernels diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp index 86ff95983d3..1a66971eed2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp @@ -23,7 +23,7 @@ #include "common/DataTypes.hpp" #include "constitutive/fluid/multifluid/Layouts.hpp" #include "constitutive/capillaryPressure/layouts.hpp" - + namespace geos @@ -44,78 +44,78 @@ struct PotGrad GEOS_HOST_DEVICE static void compute ( real64 const & gravCoef, - real64 const & gravCoefNext, - real64 const & pres, - real64 const & presNext, - real64 const & totalMassDens, - real64 const & totalMassDensNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, - real64 & potDiff, - real64 ( & dPotDiff)[2][NC+1+IS_THERMAL] ) - + real64 const & gravCoefNext, + real64 const & pres, + real64 const & presNext, + real64 const & totalMassDens, + real64 const & totalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, + arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, + real64 & potDiff, + real64 ( & dPotDiff)[2][NC+1+IS_THERMAL] ) + { - // local working variables and arrays - real64 pres[2]{}; - real64 dPres_dP[2]{}; - real64 dPres_dC[2][NC]{}; - real64 dFlux_dP[2]{}; - real64 dFlux_dC[2][NC]{}; - real64 dMult_dP[2]{}; - real64 dMult_dC[2][NC]{}; - real64 dPotDiff_dP[2]{}; - real64 dPotDiff_dC[2][NC]{}; - - real64 multiplier[2]{}; - multiplier[ElemTag::CURRENT] = 1.0; - multiplier[ElemTag::NEXT] = -1.0; - - pres[ElemTag::CURRENT] = pres; - pres[ElemTag::NEXT] = presNext; + // local working variables and arrays + real64 pres[2]{}; + real64 dPres_dP[2]{}; + real64 dPres_dC[2][NC]{}; + real64 dFlux_dP[2]{}; + real64 dFlux_dC[2][NC]{}; + real64 dMult_dP[2]{}; + real64 dMult_dC[2][NC]{}; + real64 dPotDiff_dP[2]{}; + real64 dPotDiff_dC[2][NC]{}; + + real64 multiplier[2]{}; + multiplier[ElemTag::CURRENT] = 1.0; + multiplier[ElemTag::NEXT] = -1.0; + + pres[ElemTag::CURRENT] = pres; + pres[ElemTag::NEXT] = presNext; // local working variables and arrays - real64 dAvgMassDens_dCompCurrent[NC]{}; - real64 dAvgMassDens_dCompNext[NC]{}; + real64 dAvgMassDens_dCompCurrent[NC]{}; + real64 dAvgMassDens_dCompNext[NC]{}; - // compute the average density at the interface between well elements - real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); + // compute the average density at the interface between well elements + real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); - real64 const gravD = gravCoefNext - gravCoef; - pres[0] += + real64 const gravD = gravCoefNext - gravCoef; + pres[0] += - real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDensNext[Deriv::dP]; - real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens[Deriv::dP]; - for( integer ic = 0; ic < NC; ++ic ) - { - dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDensNext[Deriv::dC+ic]; - dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens[Deriv::dC+ic]; - } + real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDensNext[Deriv::dP]; + real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens[Deriv::dP]; + for( integer ic = 0; ic < NC; ++ic ) + { + dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDensNext[Deriv::dC+ic]; + dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens[Deriv::dC+ic]; + } - // compute depth diff times acceleration - real64 const gravD = gravCoefNext - gravCoef; - - potDiff = presNext - pres - avgMassDens * gravD; - - // TODO: add friction and acceleration terms - - /* - localPresRel = ( presNext - pres - avgMassDens * gravD ); - dpot_dp_next = ( 1 - dAvgMassDens_dPresNext * gravD ); - dpot_dp_cur = ( -1 - dAvgMassDens_dPresCurrent * gravD ); - for( integer ic = 0; ic < NC; ++ic ) - { - localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; - localPresRelJacobian[TAG::CURRENT *(NC+1) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; - } - if constexpr ( IS_THERMAL ) - { - localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDensNext[Deriv::dT]; - localPresRelJacobian[TAG::CURRENT *(NC+1)+1] = 0.5 * dTotalMassDens[Deriv::dT]; - } - */ + // compute depth diff times acceleration + real64 const gravD = gravCoefNext - gravCoef; + + potDiff = presNext - pres - avgMassDens * gravD; + + // TODO: add friction and acceleration terms + + /* + localPresRel = ( presNext - pres - avgMassDens * gravD ); + dpot_dp_next = ( 1 - dAvgMassDens_dPresNext * gravD ); + dpot_dp_cur = ( -1 - dAvgMassDens_dPresCurrent * gravD ); + for( integer ic = 0; ic < NC; ++ic ) + { + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; + localPresRelJacobian[TAG::CURRENT *(NC+1) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; + } + if constexpr ( IS_THERMAL ) + { + localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDensNext[Deriv::dT]; + localPresRelJacobian[TAG::CURRENT *(NC+1)+1] = 0.5 * dTotalMassDens[Deriv::dT]; + } + */ } }; @@ -137,7 +137,7 @@ struct WellElementPhaseFlux * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction * @param potGrad potential gradient for this phase * @param phaseFlux phase flux - * @param dPhaseFlux derivatives of phase flux + * @param dPhaseFlux derivatives of phase flux */ template< integer numComp, integer IS_THERMAL > GEOS_HOST_DEVICE @@ -165,7 +165,7 @@ struct WellElementPhaseFlux real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; real64 dGravHead_dP[numFluxSupportPoints]{}; real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; - PotGrad::compute< numComp, IS_THERMAL >( gravCoef + PotGrad::compute< numComp, IS_THERMAL >( gravCoef , gravCoefNext , pres , presNext @@ -178,7 +178,7 @@ struct WellElementPhaseFlux // gravity head real64 gravHead = gravCoef - gravCoefNext - for( integer i = 0; i < numFluxSupportPoints; i++ ) + for( integer i = 0; i < numFluxSupportPoints; i++ ) { localIndex const er = seri[i]; localIndex const esr = sesri[i]; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index d544ef885be..9e5b41b77c1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -38,7 +38,7 @@ using namespace constitutive; WellSolverBase::WellSolverBase( string const & name, Group * const parent ) : SolverBase( name, parent ), -m_numPhases( 0 ), + m_numPhases( 0 ), m_numComponents( 0 ), m_numDofPerWellElement( 0 ), m_numDofPerResElement( 0 ), @@ -49,7 +49,7 @@ m_numPhases( 0 ), setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Flag indicating whether the problem is thermal or not." ); - + this->getWrapper< string >( viewKeyStruct::discretizationString() ). setInputFlag( InputFlags::FALSE ); @@ -242,225 +242,6 @@ void WellSolverBase::shutInWell( real64 const time_n, } -void WellSolverBase::assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - GEOS_MARK_FUNCTION; - if( false && m_isThermal ) - { - integer const useTotalMassEquation = 1; - string const wellDofKey = dofManager.getKey( wellElementDofName()); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - WellControls const & well_controls = getWellControls( subRegion ); - integer isProducer = well_controls.isProducer(); - string const dofKey = dofManager.getKey( CompositionalMultiphaseBase::viewKeyStruct::elemDofFieldString()); - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); - - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - int numPhases = fluid.numFluidPhases(); - int numComponents = fluid.numFluidComponents(); - - thermalCompositionalMultiphaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - numPhases, - isProducer, - dofManager.rankOffset(), - useTotalMassEquation, - wellDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - } ); - } ); - } - else if( 0 ) - { - - integer const useTotalMassEquation = 1; - string const wellDofKey = dofManager.getKey( wellElementDofName()); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - WellControls const & well_controls = getWellControls( subRegion ); - integer isProducer = well_controls.isProducer(); - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); - - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - int numPhases = fluid.numFluidPhases(); - int numComponents = fluid.numFluidComponents(); - - compositionalMultiphaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - numPhases, - isProducer, - dofManager.rankOffset(), - useTotalMassEquation, - wellDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - } ); - } ); - // then assemble the pressure relations between well elements - assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( time, dt, domain ); - - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - } - else if( 0 ) - { - integer const useTotalMassEquation = 1; - string const wellDofKey = dofManager.getKey( wellElementDofName()); - if( 1 ) - { - - - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - WellControls const & well_controls = getWellControls( subRegion ); - integer isProducer = well_controls.isProducer(); - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - int numPhases = fluid.numFluidPhases(); - int numComponents = fluid.numFluidComponents(); - if( m_isThermal ) - { - - thermalCompositionalMultiphaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - numPhases, - isProducer, - dofManager.rankOffset(), - useTotalMassEquation, - wellDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - } - else - { - compositionalMultiphaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - numPhases, - isProducer, - dofManager.rankOffset(), - useTotalMassEquation, - wellDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - } - } ); - } ); - } - else - { - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then assemble the volume balance equations - assembleVolumeBalanceTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - } - // then assemble the pressure relations between well elements - assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( time, dt, domain ); - - // then assemble the flux terms in the mass balance equations - // get a reference to the degree-of-freedom numbers - if( 0 ) - { - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - } - else - { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - WellControls const & well_controls = getWellControls( subRegion ); - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - int numComponents = fluid.numFluidComponents(); - - compositionalMultiphaseWellKernels:: - FaceBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - dt, - dofManager.rankOffset(), - useTotalMassEquation, - wellDofKey, - well_controls, - subRegion, - localMatrix, - localRhs ); - } ); - } ); - } - } - else - { - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then assemble the volume balance equations - assembleVolumeBalanceTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then assemble the pressure relations between well elements - assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( time, dt, domain ); - - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - } - - // then apply a special treatment to the wells that are shut - //shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); -} - void WellSolverBase::updateState( DomainPartition & domain ) { GEOS_MARK_FUNCTION; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index b5f6584d26e..b4db2d678f4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -180,12 +180,12 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; + virtual void assembleSystem( real64 const GEOS_UNUSED_PARAM( time ), + real64 const GEOS_UNUSED_PARAM( dt ), + DomainPartition & GEOS_UNUSED_PARAM( domain ), + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), + arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) override {}; /** * @brief assembles the flux terms for all connections between well elements @@ -212,25 +212,11 @@ class WellSolverBase : public SolverBase */ virtual void assembleAccumulationTerms( real64 const & time_n, real64 const & dt, - DomainPartition const & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) = 0; - /** - * @brief assembles the volume balance terms for all well elements - * @param domain the physical domain object - * @param dofManager degree-of-freedom manager associated with the linear system - * @param matrix the system matrix - * @param rhs the system right-hand side vector - */ - virtual void assembleVolumeBalanceTerms( real64 const & time_n, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) = 0; - /** * @brief assembles the pressure relations at all connections between well elements except at the well head * @param time_n time at the beginning of the time step diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index e19616d95cd..e0d7c3a02f8 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -76,10 +76,10 @@ setMGRStrategy() // add Reservoir m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::compositionalMultiphaseReservoirHybridFVM; } - else if( isThermal() ) + else if( isThermal() ) { m_linearSolverParameters.get().mgr.strategy = LinearSolverParameters::MGR::StrategyType::thermalCompositionalMultiphaseReservoirFVM; - + } else { @@ -252,10 +252,6 @@ assembleCouplingTerms( real64 const time_n, { using namespace compositionalMultiphaseUtilities; - using TAG = compositionalMultiphaseWellKernels::SubRegionTag; - using ROFFSET = compositionalMultiphaseWellKernels::RowOffset; - using COFFSET = compositionalMultiphaseWellKernels::ColOffset; - GEOS_THROW_IF( !Base::m_isWellTransmissibilityComputed, GEOS_FMT( "{} {}: The well transmissibility has not been computed yet", this->getCatalogName(), this->getName() ), @@ -269,11 +265,7 @@ assembleCouplingTerms( real64 const time_n, ElementRegionManager const & elemManager = mesh.getElemManager(); - integer constexpr MAX_NUM_COMP = MultiFluidBase::MAX_NUM_COMPONENTS; - integer constexpr MAX_NUM_DOF = MAX_NUM_COMP + 2; - integer const numComps = Base::wellSolver()->numFluidComponents(); - integer const resNumDofs = Base::wellSolver()->numDofPerResElement(); string const resDofKey = dofManager.getKey( Base::wellSolver()->resElementDofName() ); ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > const resDofNumberAccessor = @@ -285,7 +277,7 @@ assembleCouplingTerms( real64 const time_n, elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion const & subRegion ) { -string const & fluidName = this->flowSolver()->template getConstitutiveName< MultiFluidBase >( subRegion ); + string const & fluidName = this->flowSolver()->template getConstitutiveName< MultiFluidBase >( subRegion ); MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); // if the well is shut, we neglect reservoir-well flow that may occur despite the zero rate @@ -304,129 +296,51 @@ string const & fluidName = this->flowSolver()->template getConstitutiveName< Mul // get the degrees of freedom string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); -areWellsShut = 0; + areWellsShut = 0; - if( 0 ) + integer useTotalMassEquation1=1; + integer numCrossflowPerforations=0; + if( isThermal ( ) ) { - - - - RAJA::ReduceSum< parallelDeviceReduce, integer > numCrossflowPerforations( 0 ); - - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - // get well variables on perforations - arrayView2d< real64 const > const & compPerfRate = - perforationData->getField< fields::well::compPerforationRate >(); - arrayView3d< real64 const > const & dCompPerfRate_dPres = - perforationData->getField< fields::well::dCompPerforationRate_dPres >(); - arrayView4d< real64 const > const & dCompPerfRate_dComp = - perforationData->getField< fields::well::dCompPerforationRate_dComp >(); - //arrayView4d< real64 const > const & dCompPerfRate = - // perforationData->getField< fields::well::dCompPerforationRate >(); - arrayView1d< localIndex const > const & perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const & resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const & resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const & resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - integer const useTotalMassEquation = this->flowSolver()->useTotalMassEquation(); - - - // loop over the perforations and add the rates to the residual and jacobian - forAll< parallelDevicePolicy<> >( perforationData->size(), [=] GEOS_HOST_DEVICE ( localIndex const iperf ) + coupledReservoirAndWellKernels:: + ThermalCompositionalMultiPhaseFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComps, + wellControls.isProducer(), + dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + useTotalMassEquation1, + detectCrossflow, + numCrossflowPerforations, + localRhs, + localMatrix ); + } + else { - // local working variables and arrays - stackArray1d< localIndex, 2 * MAX_NUM_COMP > eqnRowIndices( 2 * numComps ); - stackArray1d< globalIndex, 2 * MAX_NUM_DOF > dofColIndices( 2 * resNumDofs ); - - stackArray1d< real64, 2 * MAX_NUM_COMP > localPerf( 2 * numComps ); - stackArray2d< real64, 2 * MAX_NUM_COMP * 2 * MAX_NUM_DOF > localPerfJacobian( 2 * numComps, 2 * resNumDofs ); - - // get the reservoir (sub)region and element indices - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - - // get the well element index for this perforation - localIndex const iwelem = perfWellElemIndex[iperf]; - globalIndex const resOffset = resDofNumber[er][esr][ei]; - globalIndex const wellElemOffset = wellElemDofNumber[iwelem]; - - for( integer ic = 0; ic < numComps; ++ic ) - { - eqnRowIndices[TAG::RES * numComps + ic] = LvArray::integerConversion< localIndex >( resOffset - rankOffset ) + ic; - eqnRowIndices[TAG::WELL * numComps + ic] = LvArray::integerConversion< localIndex >( wellElemOffset - rankOffset ) + ROFFSET::MASSBAL + ic; - } - for( integer jdof = 0; jdof < resNumDofs; ++jdof ) - { - dofColIndices[TAG::RES * resNumDofs + jdof] = resOffset + jdof; - dofColIndices[TAG::WELL * resNumDofs + jdof] = wellElemOffset + COFFSET::DPRES + jdof; - } - - // populate local flux vector and derivatives - for( integer ic = 0; ic < numComps; ++ic ) - { - localPerf[TAG::RES * numComps + ic] = dt * compPerfRate[iperf][ic]; - localPerf[TAG::WELL * numComps + ic] = -dt * compPerfRate[iperf][ic]; - - if( detectCrossflow ) - { - if( compPerfRate[iperf][ic] > LvArray::NumericLimits< real64 >::epsilon ) - { - numCrossflowPerforations += 1; - } - } - - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const localDofIndexPres = ke * resNumDofs; - - localPerfJacobian[TAG::RES * numComps + ic][localDofIndexPres] = dt * dCompPerfRate_dPres[iperf][ke][ic]; - localPerfJacobian[TAG::WELL * numComps + ic][localDofIndexPres] = -dt * dCompPerfRate_dPres[iperf][ke][ic]; - - for( integer jc = 0; jc < numComps; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; -//assert( fabs( dCompPerfRate_dComp[iperf][ke][ic][jc] -dCompPerfRate[iperf][ke][ic][jc] ) < FLT_EPSILON ); - localPerfJacobian[TAG::RES * numComps + ic][localDofIndexComp] = dt * dCompPerfRate_dComp[iperf][ke][ic][jc]; - localPerfJacobian[TAG::WELL * numComps + ic][localDofIndexComp] = -dt * dCompPerfRate_dComp[iperf][ke][ic][jc]; - } - } - } - - if( useTotalMassEquation ) - { - // Apply equation/variable change transformation(s) - stackArray1d< real64, 2 * MAX_NUM_DOF > work( 2 * resNumDofs ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComps, numComps, resNumDofs * 2, 2, localPerfJacobian, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComps, numComps, 2, localPerf ); - } - - for( localIndex i = 0; i < localPerf.size(); ++i ) - { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < localMatrix.numRows() ) - { - localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices.data(), - localPerfJacobian[i].dataIfContiguous(), - 2 * resNumDofs ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[eqnRowIndices[i]], localPerf[i] ); - } - } - } ); - + coupledReservoirAndWellKernels:: + IsothermalCompositionalMultiPhaseFluxKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( numComps, + dt, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + useTotalMassEquation1, + detectCrossflow, + numCrossflowPerforations, + localRhs, + localMatrix ); + } - - if( detectCrossflow ) // check to avoid communications if not needed + if( detectCrossflow ) // check to avoid communications if not needed { - globalIndex const totalNumCrossflowPerforations = MpiWrapper::sum( numCrossflowPerforations.get() ); + globalIndex const totalNumCrossflowPerforations = MpiWrapper::sum( numCrossflowPerforations ); if( totalNumCrossflowPerforations > 0 ) { GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "CompositionalMultiphaseReservoir '{}': Warning! Crossflow detected at {} perforations in well {}" @@ -435,67 +349,12 @@ areWellsShut = 0; WellControls::viewKeyStruct::enableCrossflowString(), wellControls.getName() ) ); } } - - } - else - { - integer useTotalMassEquation1=1; - integer numCrossflowPerforations=0; - if( isThermal ( ) ) - { - coupledReservoirAndWellKernels:: - ThermalCompositionalMultiPhaseFluxKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComps, - wellControls.isProducer(), - dt, - rankOffset, - wellDofKey, - subRegion, - resDofNumber, - perforationData, - fluid, - useTotalMassEquation1, - detectCrossflow, - numCrossflowPerforations, - localRhs, - localMatrix ); - } - else - { - coupledReservoirAndWellKernels:: - IsothermalCompositionalMultiPhaseFluxKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComps, - dt, - rankOffset, - wellDofKey, - subRegion, - resDofNumber, - perforationData, - fluid, - useTotalMassEquation1, - detectCrossflow, - numCrossflowPerforations, - localRhs, - localMatrix ); - } - if( detectCrossflow ) // check to avoid communications if not needed - { - globalIndex const totalNumCrossflowPerforations = MpiWrapper::sum( numCrossflowPerforations ); - if( totalNumCrossflowPerforations > 0 ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( "CompositionalMultiphaseReservoir '{}': Warning! Crossflow detected at {} perforations in well {}" - "To disable crossflow for injectors, you can use the field '{}' in the WellControls '{}' section", - this->getName(), totalNumCrossflowPerforations, subRegion.getName(), - WellControls::viewKeyStruct::enableCrossflowString(), wellControls.getName() ) ); - } - } - } - // update dynamically the MGR recipe to optimize the linear solve if all wells are shut - areWellsShut = MpiWrapper::min( areWellsShut ); - m_linearSolverParameters.get().mgr.areWellsShut = areWellsShut; -} ); + // update dynamically the MGR recipe to optimize the linear solve if all wells are shut + areWellsShut = MpiWrapper::min( areWellsShut ); + m_linearSolverParameters.get().mgr.areWellsShut = areWellsShut; + } ); } ); } diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 816a280c0c1..7077232c35a 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -22,7 +22,7 @@ #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/SolverBaseKernels.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellTags.hpp" @@ -41,14 +41,14 @@ using namespace constitutive; * @brief Define the interface for the assembly kernel in charge of flux terms */ template< integer NC, integer IS_THERMAL > -class IsothermalCompositionalMultiPhaseFluxKernel +class IsothermalCompositionalMultiPhaseFluxKernel { public: - - /// Compile time value for the number of components + + /// Compile time value for the number of components static constexpr integer numComp = NC; static constexpr integer resNumDOF = NC+1+IS_THERMAL; - + // Well jacobian column and row indicies using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; @@ -83,25 +83,23 @@ class IsothermalCompositionalMultiPhaseFluxKernel * @param[in] kernelFlags flags packed together */ IsothermalCompositionalMultiPhaseFluxKernel( real64 const dt, - globalIndex const rankOffset, - string const wellDofKey, - WellElementSubRegion const & subRegion, - ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, - PerforationData const * const perforationData, - MultiFluidBase const & fluid, - - arrayView1d< real64 > const & localRhs, - CRSMatrixView< real64, globalIndex const > const & localMatrix, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix, bool const & detectCrossflow, - integer & numCrossFlowPerforations, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + integer & numCrossFlowPerforations, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) : m_dt( dt ), m_numPhases ( fluid.numFluidPhases()), m_rankOffset( rankOffset ), m_compPerfRate( perforationData->getField< fields::well::compPerforationRate >() ), - m_dCompPerfRate_dPres( perforationData->getField< fields::well::dCompPerforationRate_dPres >() ), - m_dCompPerfRate_dComp( perforationData->getField< fields::well::dCompPerforationRate_dComp >() ), m_dCompPerfRate( perforationData->getField< fields::well::dCompPerforationRate >() ), m_perfWellElemIndex( perforationData->getField< fields::perforation::wellElementIndex >() ), m_wellElemDofNumber( subRegion.getReference< array1d< globalIndex > >( wellDofKey ) ), @@ -116,7 +114,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) { } - + /** * @brief Compute the local flux contributions to the residual and Jacobian * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes @@ -132,120 +130,97 @@ class IsothermalCompositionalMultiPhaseFluxKernel FUNC && compFluxKernelOp = NoOpFunc{} ) const { - using namespace compositionalMultiphaseUtilities; - // local working variables and arrays - stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 * numComp ); - stackArray1d< globalIndex, 2*resNumDOF > dofColIndices( 2 * resNumDOF ); + using namespace compositionalMultiphaseUtilities; + // local working variables and arrays + stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 * numComp ); + stackArray1d< globalIndex, 2*resNumDOF > dofColIndices( 2 * resNumDOF ); - stackArray1d< real64, 2 * numComp > localPerf( 2 * numComp ); - stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2 * numComp, 2 * resNumDOF ); + stackArray1d< real64, 2 * numComp > localPerf( 2 * numComp ); + stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2 * numComp, 2 * resNumDOF ); - // get the reservoir (sub)region and element indices - localIndex const er = m_resElementRegion[iperf]; - localIndex const esr = m_resElementSubRegion[iperf]; - localIndex const ei = m_resElementIndex[iperf]; + // get the reservoir (sub)region and element indices + localIndex const er = m_resElementRegion[iperf]; + localIndex const esr = m_resElementSubRegion[iperf]; + localIndex const ei = m_resElementIndex[iperf]; - // get the well element index for this perforation - localIndex const iwelem = m_perfWellElemIndex[iperf]; - globalIndex const resOffset = m_resElemDofNumber[er][esr][ei]; - globalIndex const wellElemOffset = m_wellElemDofNumber[iwelem]; + // get the well element index for this perforation + localIndex const iwelem = m_perfWellElemIndex[iperf]; + globalIndex const resOffset = m_resElemDofNumber[er][esr][ei]; + globalIndex const wellElemOffset = m_wellElemDofNumber[iwelem]; - for( integer ic = 0; ic < numComp; ++ic ) - { - eqnRowIndices[TAG::RES * numComp + ic] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + ic; - eqnRowIndices[TAG::WELL * numComp + ic] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::MASSBAL + ic; - } - // Note res and well have same col lineup for P and compdens - for( integer jdof = 0; jdof < NC+1; ++jdof ) + for( integer ic = 0; ic < numComp; ++ic ) + { + eqnRowIndices[TAG::RES * numComp + ic] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + ic; + eqnRowIndices[TAG::WELL * numComp + ic] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::MASSBAL + ic; + } + // Note res and well have same col lineup for P and compdens + for( integer jdof = 0; jdof < NC+1; ++jdof ) + { + dofColIndices[TAG::RES * resNumDOF + jdof] = resOffset + jdof; + dofColIndices[TAG::WELL * resNumDOF + jdof] = wellElemOffset + WJ_COFFSET::dP + jdof; + } + // For temp its different + if constexpr ( IS_THERMAL ) + { + dofColIndices[TAG::RES * resNumDOF + NC+1 ] = resOffset + NC+1; + dofColIndices[TAG::WELL * resNumDOF + NC+1 ] = wellElemOffset + WJ_COFFSET::dT; + } + // populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + localPerf[TAG::RES * numComp + ic] = m_dt * m_compPerfRate[iperf][ic]; + localPerf[TAG::WELL * numComp + ic] = -m_dt * m_compPerfRate[iperf][ic]; + + if( m_detectCrossflow ) + { + if( m_compPerfRate[iperf][ic] > LvArray::NumericLimits< real64 >::epsilon ) { - dofColIndices[TAG::RES * resNumDOF + jdof] = resOffset + jdof; - dofColIndices[TAG::WELL * resNumDOF + jdof] = wellElemOffset + WJ_COFFSET::dP + jdof; + m_numCrossFlowPerforations += 1; } - // For temp its different - if constexpr ( IS_THERMAL ) + } + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex localDofIndexPres = ke * resNumDOF; + + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexPres] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexPres] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; + for( integer jc = 0; jc < numComp; ++jc ) { - dofColIndices[TAG::RES * resNumDOF + NC+1 ] = resOffset + NC+1; - dofColIndices[TAG::WELL * resNumDOF + NC+1 ] = wellElemOffset + WJ_COFFSET::dT; + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; } - // populate local flux vector and derivatives - for( integer ic = 0; ic < numComp; ++ic ) + if constexpr ( IS_THERMAL ) { - localPerf[TAG::RES * numComp + ic] = m_dt * m_compPerfRate[iperf][ic]; - localPerf[TAG::WELL * numComp + ic] = -m_dt * m_compPerfRate[iperf][ic]; - - if( m_detectCrossflow ) - { - if( m_compPerfRate[iperf][ic] > LvArray::NumericLimits< real64 >::epsilon ) - { - m_numCrossFlowPerforations += 1; - } - } - if( 0 ) - { - - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const localDofIndexPres = ke * resNumDOF; - - localPerfJacobian[TAG::RES * numComp + ic][localDofIndexPres] = m_dt * m_dCompPerfRate_dPres[iperf][ke][ic]; - localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexPres] = -m_dt * m_dCompPerfRate_dPres[iperf][ke][ic]; - assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP] - m_dCompPerfRate_dPres[iperf][ke][ic] ) < FLT_EPSILON ); - for( integer jc = 0; jc < numComp; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] - m_dCompPerfRate_dComp[iperf][ke][ic][jc] ) < FLT_EPSILON ); - localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate_dComp[iperf][ke][ic][jc]; - localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate_dComp[iperf][ke][ic][jc]; - } - } - } - else - { - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex localDofIndexPres = ke * resNumDOF; - - localPerfJacobian[TAG::RES * numComp + ic][localDofIndexPres] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; - localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexPres] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP]; - assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dP] - m_dCompPerfRate_dPres[iperf][ke][ic] ) < FLT_EPSILON ); - for( integer jc = 0; jc < numComp; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - assert( fabs( m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc] - m_dCompPerfRate_dComp[iperf][ke][ic][jc] ) < FLT_EPSILON ); - localPerfJacobian[TAG::RES * numComp + ic][localDofIndexComp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; - localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexComp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dC+jc]; - } - if constexpr ( IS_THERMAL ) - { - localIndex localDofIndexTemp = localDofIndexPres + NC + 1; - localPerfJacobian[TAG::RES * numComp + ic][localDofIndexTemp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; - localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexTemp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; - } - } - } + localIndex localDofIndexTemp = localDofIndexPres + NC + 1; + localPerfJacobian[TAG::RES * numComp + ic][localDofIndexTemp] = m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; + localPerfJacobian[TAG::WELL * numComp + ic][localDofIndexTemp] = -m_dt * m_dCompPerfRate[iperf][ke][ic][CP_Deriv::dT]; } + } + } - if( m_useTotalMassEquation ) - { - // Apply equation/variable change transformation(s) - stackArray1d< real64, 2 * resNumDOF > work( 2 * resNumDOF ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp, resNumDOF * 2, 2, localPerfJacobian, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numComp, 2, localPerf ); - } + if( m_useTotalMassEquation ) + { + // Apply equation/variable change transformation(s) + stackArray1d< real64, 2 * resNumDOF > work( 2 * resNumDOF ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numComp, resNumDOF * 2, 2, localPerfJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numComp, 2, localPerf ); + } - for( localIndex i = 0; i < localPerf.size(); ++i ) - { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) - { - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices.data(), - localPerfJacobian[i].dataIfContiguous(), - 2 * resNumDOF ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); - } - } + for( localIndex i = 0; i < localPerf.size(); ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) + { + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices.data(), + localPerfJacobian[i].dataIfContiguous(), + 2 * resNumDOF ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); + } + } compFluxKernelOp( resOffset, wellElemOffset, dofColIndices, iwelem ); - + } @@ -281,8 +256,6 @@ class IsothermalCompositionalMultiPhaseFluxKernel globalIndex const m_rankOffset; // Perfoation variables arrayView2d< real64 const > const m_compPerfRate; - arrayView3d< real64 const > const m_dCompPerfRate_dPres; - arrayView4d< real64 const > const m_dCompPerfRate_dComp; arrayView4d< real64 const > const m_dCompPerfRate; arrayView1d< localIndex const > const m_perfWellElemIndex; @@ -326,18 +299,18 @@ class IsothermalCompositionalMultiPhaseFluxKernelFactory static void createAndLaunch( integer const numComps, real64 const dt, - globalIndex const rankOffset, - string const wellDofKey, - WellElementSubRegion const & subRegion, - ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, - PerforationData const * const perforationData, - MultiFluidBase const & fluid, - integer const & useTotalMassEquation, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + integer const & useTotalMassEquation, bool const & detectCrossflow, - integer & numCrossFlowPerforations, - arrayView1d< real64 > const & localRhs, - CRSMatrixView< real64, globalIndex const > const & localMatrix - ) + integer & numCrossFlowPerforations, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix + ) { isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { @@ -359,7 +332,7 @@ class IsothermalCompositionalMultiPhaseFluxKernelFactory } }; - + /** * @class FaceBasedAssemblyKernel * @tparam NUM_COMP number of fluid components @@ -370,10 +343,10 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM { public: using Base = IsothermalCompositionalMultiPhaseFluxKernel< NC, IS_THERMAL >; - /// Compile time value for the number of components + /// Compile time value for the number of components static constexpr integer numComp = NC; static constexpr integer resNumDOF = NC+1+IS_THERMAL; - + // Well jacobian column and row indicies using WJ_COFFSET = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >; using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >; @@ -389,8 +362,8 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM using Base::m_localRhs; using Base::m_localMatrix; using Base::m_rankOffset; - - + + /// Compute time value for the number of degrees of freedom static constexpr integer numDof = WJ_COFFSET::nDer; @@ -412,38 +385,38 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM * @param[inout] localRhs the local right-hand side vector * @param[in] kernelFlags flags packed together */ - ThermalCompositionalMultiPhaseFluxKernel( real64 const dt, + ThermalCompositionalMultiPhaseFluxKernel( real64 const dt, integer const isProducer, - globalIndex const rankOffset, - string const wellDofKey, - WellElementSubRegion const & subRegion, - ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, - PerforationData const * const perforationData, - MultiFluidBase const & fluid, - arrayView1d< real64 > const & localRhs, - CRSMatrixView< real64, globalIndex const > const & localMatrix, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix, bool const & detectCrossflow, - integer & numCrossFlowPerforations, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + integer & numCrossFlowPerforations, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) : Base( dt, - rankOffset, - wellDofKey, - subRegion, - resDofNumber, - perforationData, - fluid, - localRhs, - localMatrix, + rankOffset, + wellDofKey, + subRegion, + resDofNumber, + perforationData, + fluid, + localRhs, + localMatrix, detectCrossflow, - numCrossFlowPerforations, - kernelFlags ), + numCrossFlowPerforations, + kernelFlags ), m_isProducer( isProducer ), m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) { } - + /** * @brief Compute the local flux contributions to the residual and Jacobian * @tparam FUNC the type of the function that can be used to customize the computation of the phase fluxes @@ -466,55 +439,55 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM { return; } - // local working variables and arrays + // local working variables and arrays stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 ); stackArray1d< real64, 2 * numComp > localPerf( 2 ); stackArray2d< real64, 2 * resNumDOF * 2 * numComp > localPerfJacobian( 2, 2 * resNumDOF ); - - // equantion offsets - note res and well have different equation lineups - eqnRowIndices[TAG::RES ] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + NC + 1; - eqnRowIndices[TAG::WELL ] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::ENERGYBAL; - // populate local flux vector and derivatives - localPerf[TAG::RES ] = m_dt * m_energyPerfFlux[iperf]; - localPerf[TAG::WELL ] = -m_dt * m_energyPerfFlux[iperf]; + // equantion offsets - note res and well have different equation lineups + eqnRowIndices[TAG::RES ] = LvArray::integerConversion< localIndex >( resOffset - m_rankOffset ) + NC + 1; + eqnRowIndices[TAG::WELL ] = LvArray::integerConversion< localIndex >( wellElemOffset - m_rankOffset ) + WJ_ROFFSET::ENERGYBAL; + + // populate local flux vector and derivatives + localPerf[TAG::RES ] = m_dt * m_energyPerfFlux[iperf]; + localPerf[TAG::WELL ] = -m_dt * m_energyPerfFlux[iperf]; - for( integer ke = 0; ke < 2; ++ke ) + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex localDofIndexPres = ke * resNumDOF; + localPerfJacobian[TAG::RES ][localDofIndexPres] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; + localPerfJacobian[TAG::WELL ][localDofIndexPres] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; + //localDofIndexPres += 1; + // populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) { - localIndex localDofIndexPres = ke * resNumDOF; - localPerfJacobian[TAG::RES ][localDofIndexPres] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; - localPerfJacobian[TAG::WELL ][localDofIndexPres] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; - //localDofIndexPres += 1; - // populate local flux vector and derivatives - for( integer ic = 0; ic < numComp; ++ic ) - { - localIndex const localDofIndexComp = localDofIndexPres + ic + 1; + localIndex const localDofIndexComp = localDofIndexPres + ic + 1; localPerfJacobian[TAG::RES ][localDofIndexComp] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic]; localPerfJacobian[TAG::WELL][localDofIndexComp] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dC+ic]; - } + } localPerfJacobian[TAG::RES ][localDofIndexPres+NC+1] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT]; localPerfJacobian[TAG::WELL][localDofIndexPres+NC+1] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dT]; - } - - - for( localIndex i = 0; i < localPerf.size(); ++i ) + } + + + for( localIndex i = 0; i < localPerf.size(); ++i ) + { + if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) { - if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() ) - { - m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], - dofColIndices.data(), - localPerfJacobian[i].dataIfContiguous(), - 2 * resNumDOF ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); - } + m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i], + dofColIndices.data(), + localPerfJacobian[i].dataIfContiguous(), + 2 * resNumDOF ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], localPerf[i] ); } + } } ); - - + + } - + /** * @brief Performs the kernel launch @@ -572,18 +545,18 @@ class ThermalCompositionalMultiPhaseFluxKernelFactory createAndLaunch( integer const numComps, integer const isProducer, real64 const dt, - globalIndex const rankOffset, - string const wellDofKey, - WellElementSubRegion const & subRegion, - ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, - PerforationData const * const perforationData, - MultiFluidBase const & fluid, - integer const & useTotalMassEquation, + globalIndex const rankOffset, + string const wellDofKey, + WellElementSubRegion const & subRegion, + ElementRegionManager::ElementViewConst< arrayView1d< globalIndex const > > const resDofNumber, + PerforationData const * const perforationData, + MultiFluidBase const & fluid, + integer const & useTotalMassEquation, bool const & detectCrossflow, - integer & numCrossFlowPerforations, - arrayView1d< real64 > const & localRhs, - CRSMatrixView< real64, globalIndex const > const & localMatrix - ) + integer & numCrossFlowPerforations, + arrayView1d< real64 > const & localRhs, + CRSMatrixView< real64, globalIndex const > const & localMatrix + ) { isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC ) { diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp index b707da443e2..1c131e06f46 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp @@ -136,78 +136,78 @@ addCouplingSparsityPattern( DomainPartition const & domain, string const resDofKey = dofManager.getKey( Base::wellSolver()->resElementDofName() ); string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); -integer isThermal = Base::wellSolver()->isThermal(); + integer isThermal = Base::wellSolver()->isThermal(); integer const wellNDOF = Base::wellSolver()->numDofPerWellElement(); ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > const & resDofNumber = elemManager.constructArrayViewAccessor< globalIndex, 1 >( resDofKey ); globalIndex const rankOffset = dofManager.rankOffset(); -geos::internal::kernelLaunchSelectorThermalSwitch( isThermal, [&] ( auto ISTHERMAL ) { + geos::internal::kernelLaunchSelectorThermalSwitch( isThermal, [&] ( auto ISTHERMAL ) { integer constexpr IS_THERMAL = ISTHERMAL(); - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - PerforationData const * const perforationData = subRegion.getPerforationData(); - - // get the well degrees of freedom and ghosting info - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - // get the well element indices corresponding to each perforation - arrayView1d< localIndex const > const & perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const & resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const & resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const & resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - // Insert the entries corresponding to reservoir-well perforations - // This will fill J_WR, and J_RW - forAll< serialPolicy >( perforationData->size(), [=] ( localIndex const iperf ) + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion const & subRegion ) { - // Get the reservoir (sub)region and element indices - localIndex const er = resElementRegion[iperf]; - localIndex const esr = resElementSubRegion[iperf]; - localIndex const ei = resElementIndex[iperf]; - localIndex const iwelem = perfWellElemIndex[iperf]; + PerforationData const * const perforationData = subRegion.getPerforationData(); + + // get the well degrees of freedom and ghosting info + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the well element indices corresponding to each perforation + arrayView1d< localIndex const > const & perfWellElemIndex = + perforationData->getField< fields::perforation::wellElementIndex >(); + + // get the element region, subregion, index + arrayView1d< localIndex const > const & resElementRegion = + perforationData->getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const & resElementSubRegion = + perforationData->getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const & resElementIndex = + perforationData->getField< fields::perforation::reservoirElementIndex >(); + + // Insert the entries corresponding to reservoir-well perforations + // This will fill J_WR, and J_RW + forAll< serialPolicy >( perforationData->size(), [=] ( localIndex const iperf ) + { + // Get the reservoir (sub)region and element indices + localIndex const er = resElementRegion[iperf]; + localIndex const esr = resElementSubRegion[iperf]; + localIndex const ei = resElementIndex[iperf]; + localIndex const iwelem = perfWellElemIndex[iperf]; - globalIndex const eqnRowIndexRes = resDofNumber[er][esr][ei] - rankOffset; - globalIndex const dofColIndexRes = resDofNumber[er][esr][ei]; + globalIndex const eqnRowIndexRes = resDofNumber[er][esr][ei] - rankOffset; + globalIndex const dofColIndexRes = resDofNumber[er][esr][ei]; - // working arrays - tjb previously dim was 2 - stackArray1d< globalIndex, 2+IS_THERMAL > eqnRowIndicesWell( wellNDOF ); - stackArray1d< globalIndex, 2+IS_THERMAL > dofColIndicesWell( wellNDOF ); + // working arrays - tjb previously dim was 2 + stackArray1d< globalIndex, 2+IS_THERMAL > eqnRowIndicesWell( wellNDOF ); + stackArray1d< globalIndex, 2+IS_THERMAL > dofColIndicesWell( wellNDOF ); - for( integer idof = 0; idof < wellNDOF; ++idof ) - { - eqnRowIndicesWell[idof] = wellElemDofNumber[iwelem] + idof - rankOffset; - dofColIndicesWell[idof] = wellElemDofNumber[iwelem] + idof; - } + for( integer idof = 0; idof < wellNDOF; ++idof ) + { + eqnRowIndicesWell[idof] = wellElemDofNumber[iwelem] + idof - rankOffset; + dofColIndicesWell[idof] = wellElemDofNumber[iwelem] + idof; + } - if( eqnRowIndexRes >= 0 && eqnRowIndexRes < pattern.numRows() ) - { - for( localIndex j = 0; j < dofColIndicesWell.size(); ++j ) + if( eqnRowIndexRes >= 0 && eqnRowIndexRes < pattern.numRows() ) { - pattern.insertNonZero( eqnRowIndexRes, dofColIndicesWell[j] ); + for( localIndex j = 0; j < dofColIndicesWell.size(); ++j ) + { + pattern.insertNonZero( eqnRowIndexRes, dofColIndicesWell[j] ); + } } - } - for( localIndex i = 0; i < eqnRowIndicesWell.size(); ++i ) - { - if( eqnRowIndicesWell[i] >= 0 && eqnRowIndicesWell[i] < pattern.numRows() ) + for( localIndex i = 0; i < eqnRowIndicesWell.size(); ++i ) { - pattern.insertNonZero( eqnRowIndicesWell[i], dofColIndexRes ); + if( eqnRowIndicesWell[i] >= 0 && eqnRowIndicesWell[i] < pattern.numRows() ) + { + pattern.insertNonZero( eqnRowIndicesWell[i], dofColIndexRes ); + } } - } + } ); } ); } ); } ); -} ); } template< typename RESERVOIR_SOLVER > diff --git a/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp index 1b686912661..e3304b31842 100644 --- a/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp @@ -532,20 +532,6 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux } -TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_VolumeBalance ) -{ - real64 const perturb = std::sqrt( eps ); - real64 const tol = 1e-1; // 10% error margin - - DomainPartition & domain = state.getProblemManager().getDomainPartition(); - - testNumericalJacobian( *solver, domain, perturb, tol, - [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - solver->wellSolver()->assembleVolumeBalanceTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); - } ); -} TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) { diff --git a/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp index da4c20aa094..ea889aa19d1 100644 --- a/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testReservoirSinglePhaseMSWells.cpp @@ -384,7 +384,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleFluxTerms(TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleFluxTerms( TIME, DT, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } From 0ec258e7875cfea9c63c13662bab1f1c05e1d5fd Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Fri, 31 May 2024 10:11:34 -0700 Subject: [PATCH 21/71] Use phase fraction not phase vol fraction ..and ders --- .../wells/PerforationFluxKernels.hpp | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index bc6a69022b9..eaa5787499e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -523,10 +523,10 @@ class PerforationFluxKernel { for( integer ip = 0; ip < NP; ++ip ) { - bool const phaseExists = stack.m_wellElemPhaseVolFrac[iwelem][ip] > 0.0; + bool const phaseExists = stack.m_wellElemPhaseFrac[iwelem][0][ip] > 0.0; if( !phaseExists ) continue; - double pflux = stack.m_wellElemPhaseVolFrac[iwelem][ip]*flux; + double pflux = stack.m_wellElemPhaseFrac[iwelem][0][ip]*flux; real64 const wellelem_enthalpy = stack.m_wellElemPhaseEnthalpy[iwelem][0][ip]; stack.m_energyPerfFlux[iperf] += pflux * wellelem_enthalpy; @@ -536,21 +536,21 @@ class PerforationFluxKernel stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dP] - + pflux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dP]; + + pflux * wellelem_enthalpy * stack.m_dPhaseFrac[iwelem][0][ip][Deriv::dP]; stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dT] - + pflux * wellelem_enthalpy * stack.m_dPhaseVolFrac[iwelem][ip][Deriv::dT]; + + pflux * wellelem_enthalpy * stack.m_dPhaseFrac[iwelem][0][ip][Deriv::dT]; //energy e real64 dPVF_dC[numComp]{}; applyChainRule( NC, m_dWellElemCompFrac_dCompDens[iwelem], - stack.m_dPhaseVolFrac[iwelem][ip], + stack.m_dPhaseFrac[iwelem][0][ip], dPVF_dC, Deriv::dC ); for( integer ic=0; ic()), - m_dPhaseVolFrac( subRegion.getField< fields::well::dPhaseVolumeFraction >() ), + m_wellElemPhaseFrac( fluid.phaseFraction() ), + m_dPhaseFrac( fluid.dPhaseFraction() ), m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), @@ -781,8 +779,9 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati {} /// Views on well element properties - arrayView2d< real64 const, compflow::USD_PHASE > m_wellElemPhaseVolFrac; - arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; + /// Element phase fraction + arrayView3d< real64 const, multifluid::USD_PHASE > const m_wellElemPhaseFrac; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFrac; arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; From a489169569fa02a56eb557dd49fc6fa94d408fed Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Mon, 3 Jun 2024 07:28:04 -0700 Subject: [PATCH 22/71] fix for spe11b --- .../fluid/multifluid/MultiFluidBase.hpp | 4 +++ ...rmalCompositionalMultiphaseBaseKernels.hpp | 2 -- .../wells/CompositionalMultiphaseWell.cpp | 26 ++++++++++++++++--- ...rmalCompositionalMultiphaseWellKernels.hpp | 2 ++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp index e31d513cd3b..8127fa76b75 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp @@ -1054,6 +1054,10 @@ MultiFluidBase::KernelWrapper:: bool const phaseExists = (phaseFrac.value[ip] > 0); if( !phaseExists ) { + for( integer idof = 0; idof < numDOF; ++idof ) + { + phaseInternalEnergy.derivs[ip][idof] = 0.0; + } continue; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp index 5948b875498..98a981b95c3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ThermalCompositionalMultiphaseBaseKernels.hpp @@ -320,13 +320,11 @@ class ElementBasedAssemblyKernel : public isothermalCompositionalMultiphaseBaseK stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; // derivatives w.r.t. component densities - //std::cout << "res " << dPhaseInternalEnergy[ip][Deriv::dC] << " " << dPhaseInternalEnergy[ip][Deriv::dC+1] << std::endl; applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); for( integer jc = 0; jc < numComp; ++jc ) { stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount_dC[jc] + dPhaseInternalEnergy_dC[jc] * phaseAmount; - //std::cout << "phase " << ip << " jc " << jc << " " << stack.localJacobian[numEqn-1][jc + 1] << std::endl; } } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 981854c7e75..8435b583d30 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -854,16 +854,29 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRegion ) { GEOS_MARK_FUNCTION; - + using Deriv = multifluid::DerivativeOffset; arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); arrayView1d< real64 const > const & temp = subRegion.getField< fields::well::temperature >(); arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >(); arrayView2d< real64 const, compflow::USD_COMP > const & pvFrac = subRegion.getField< fields::well::phaseVolumeFraction >(); arrayView2d< real64 const, compflow::USD_COMP > const & compDens = subRegion.getField< fields::well::globalCompDensity >(); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); + arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy=fluid.phaseInternalEnergy(); + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy=fluid.dPhaseInternalEnergy(); + std::cout << subRegion.getName() << std::endl; + + for( integer i=0; i Date: Mon, 3 Jun 2024 07:49:35 -0700 Subject: [PATCH 23/71] fix pedantry --- .../multiphysics/CoupledReservoirAndWellKernels.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 7077232c35a..3a977c76ada 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -578,7 +578,7 @@ class ThermalCompositionalMultiPhaseFluxKernelFactory } }; -}; // end namespace coupledReservoirAndWellKernels +} // end namespace coupledReservoirAndWellKernels } // end namespace geos From 32ae6b968d6ca42e3f61c6fbd460ae3290526f05 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 5 Jun 2024 08:48:06 -0700 Subject: [PATCH 24/71] 1) add Aww numerical derivative unit tests, 2) thermal index fix --- .../wells/CompositionalMultiphaseWell.cpp | 57 +- .../wells/CompositionalMultiphaseWell.hpp | 2 + .../CompositionalMultiphaseWellKernels.hpp | 3 +- ...rmalCompositionalMultiphaseWellKernels.hpp | 6 +- ...mpositionalMultiphaseReservoirAndWells.cpp | 6 +- .../unitTests/wellsTests/CMakeLists.txt | 6 +- .../unitTests/wellsTests/co2flash.txt | 1 + .../unitTests/wellsTests/pvtgas.txt | 3 + .../unitTests/wellsTests/pvtliquid.txt | 3 + ...eservoirCompositionalMultiphaseMSWells.cpp | 651 ++++++++++++++ ...eservoirCompositionalMultiphaseSSWells.cpp | 743 ++++++++++++++++ ...eservoirCompositionalMultiphaseMSWells.cpp | 797 ++++++++++++++++++ ...eservoirCompositionalMultiphaseSSWells.cpp | 784 +++++++++++++++++ 13 files changed, 2999 insertions(+), 63 deletions(-) create mode 100644 src/coreComponents/unitTests/wellsTests/co2flash.txt create mode 100644 src/coreComponents/unitTests/wellsTests/pvtgas.txt create mode 100644 src/coreComponents/unitTests/wellsTests/pvtliquid.txt create mode 100644 src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp create mode 100644 src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp create mode 100644 src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp create mode 100644 src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 8435b583d30..bb013dd5a2c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -970,60 +970,9 @@ void CompositionalMultiphaseWell::assembleSystem( real64 const time, // then assemble the flux terms in the mass balance equations // get a reference to the degree-of-freedom numbers - if( 0 ) - { - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - } - else - { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) - { - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); - MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); - int numComponents = fluid.numFluidComponents(); - WellControls const & well_controls = getWellControls( subRegion ); - if( well_controls.isWellOpen( time+ dt ) ) - { - if( isThermal() ) - { - thermalCompositionalMultiphaseWellKernels:: - FaceBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - dt, - dofManager.rankOffset(), - m_useTotalMassEquation, - wellDofKey, - well_controls, - subRegion, - fluid, - localMatrix, - localRhs ); - } - else - { - compositionalMultiphaseWellKernels:: - FaceBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( numComponents, - dt, - dofManager.rankOffset(), - m_useTotalMassEquation, - wellDofKey, - well_controls, - subRegion, - localMatrix, - localRhs ); - } - } - } ); - } ); - } + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); + } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index b94acb95852..a240c6b729b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -201,6 +201,8 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual localIndex numFluidPhases() const override { return m_numPhases; } + integer useTotalMassEquation() const { return m_useTotalMassEquation; } + virtual void assembleSystem( real64 const time, real64 const dt, DomainPartition & domain, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index f2b82b6ccd2..5a4542656a7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -1170,7 +1170,7 @@ class ElementBasedAssemblyKernel integer const numRows = numComp+1+ IS_THERMAL; - if constexpr (IS_THERMAL) + if constexpr ( IS_THERMAL) { if( ei == 0 && !m_isProducer ) { @@ -1744,6 +1744,7 @@ class FaceBasedAssemblyKernel for( integer jc = 0; jc < NC; ++jc ) { dCompFlux[ic][WJ_COFFSET::dC+jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; + dComp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; } } } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 28ef02a49fa..a0eef7ebbee 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -566,8 +566,6 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT; // derivatives w.r.t. component densities - std::cout << ip << " tt " << dCompFrac_dCompDens[0][0] << " " << dCompFrac_dCompDens[0][1]<< " " << dCompFrac_dCompDens[1][0] << " " << dCompFrac_dCompDens[1][1] << - " " << dPhaseInternalEnergy[ip][Deriv::dC ] << " " << dPhaseInternalEnergy[ip][Deriv::dC+1] << std::endl; applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC ); for( integer jc = 0; jc < numComp; ++jc ) { @@ -992,9 +990,9 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB for( integer dof=0; dof < numComp; dof++ ) { - stack.localEnergyFluxJacobian[TAG::NEXT ][dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] + stack.localEnergyFluxJacobian[TAG::NEXT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; - stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] + stack.localEnergyFluxJacobian[TAG::CURRENT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; } } diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index e0d7c3a02f8..036bcc8205b 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -298,7 +298,7 @@ assembleCouplingTerms( real64 const time_n, string const wellDofKey = dofManager.getKey( Base::wellSolver()->wellElementDofName() ); areWellsShut = 0; - integer useTotalMassEquation1=1; + integer useTotalMassEquation=Base::wellSolver()->useTotalMassEquation(); integer numCrossflowPerforations=0; if( isThermal ( ) ) { @@ -313,7 +313,7 @@ assembleCouplingTerms( real64 const time_n, resDofNumber, perforationData, fluid, - useTotalMassEquation1, + useTotalMassEquation, detectCrossflow, numCrossflowPerforations, localRhs, @@ -331,7 +331,7 @@ assembleCouplingTerms( real64 const time_n, resDofNumber, perforationData, fluid, - useTotalMassEquation1, + useTotalMassEquation, detectCrossflow, numCrossflowPerforations, localRhs, diff --git a/src/coreComponents/unitTests/wellsTests/CMakeLists.txt b/src/coreComponents/unitTests/wellsTests/CMakeLists.txt index dcf6a699034..0e1e10530c9 100644 --- a/src/coreComponents/unitTests/wellsTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/wellsTests/CMakeLists.txt @@ -13,7 +13,11 @@ endif() if( ENABLE_PVTPackage ) list( APPEND gtest_geosx_tests - testReservoirCompositionalMultiphaseMSWells.cpp ) + testReservoirCompositionalMultiphaseMSWells.cpp + testIsothermalReservoirCompositionalMultiphaseMSWells.cpp + testIsothermalReservoirCompositionalMultiphaseSSWells.cpp + testThermalReservoirCompositionalMultiphaseSSWells.cpp + testThermalReservoirCompositionalMultiphaseMSWells.cpp ) list( APPEND dependencyList PVTPackage ) endif() diff --git a/src/coreComponents/unitTests/wellsTests/co2flash.txt b/src/coreComponents/unitTests/wellsTests/co2flash.txt new file mode 100644 index 00000000000..4c5a766d852 --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/co2flash.txt @@ -0,0 +1 @@ +FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0 diff --git a/src/coreComponents/unitTests/wellsTests/pvtgas.txt b/src/coreComponents/unitTests/wellsTests/pvtgas.txt new file mode 100644 index 00000000000..ccd4e817f67 --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/pvtgas.txt @@ -0,0 +1,3 @@ +DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10 +ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10 +EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10 diff --git a/src/coreComponents/unitTests/wellsTests/pvtliquid.txt b/src/coreComponents/unitTests/wellsTests/pvtliquid.txt new file mode 100644 index 00000000000..4df0c25f042 --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/pvtliquid.txt @@ -0,0 +1,3 @@ +DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0 +ViscosityFun PhillipsBrineViscosity 0 +EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0 diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp new file mode 100644 index 00000000000..c22603b903a --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp @@ -0,0 +1,651 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::well::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::well::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } + } ); + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + } + + // b) compute all the derivatives wrt to the connection in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = *state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleFluxTerms( dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif + +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp new file mode 100644 index 00000000000..a440c8b7c98 --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp @@ -0,0 +1,743 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + + + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + if( 1 ) + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::well::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & temp = + subRegion.getField< fields::well::temperature >(); + temp.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::well::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + if( 1 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + if( 0 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the temperature of the element + real64 const dT = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dT; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dT, + jacobianFD.toViewConstSizes() ); + } + + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } + } ); + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + if( 1 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter*wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + if( 0 ) + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + } + } + + // b) compute all the derivatives wrt to the connection in WELL elem iwelem + if( 1 ) + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 1 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + //solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif + +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleFluxTerms( dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_VolumeBalance ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleVolumeBalanceTerms( domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +#if 0 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp new file mode 100644 index 00000000000..1ab87fc151a --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -0,0 +1,797 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + + + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, bool diag_check, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + if (1) + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + std::cout << mesh.getName() << " " ; + ElementRegionManager & elemManager = mesh.getElemManager(); + std::cout << elemManager.getName() << std::endl; + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + std::cout << " " << subRegion.getName() << " " << subRegion.size() << std::endl; + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::flow::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & temp = + subRegion.getField< fields::flow::temperature >(); + temp.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + if ( ei !=0 ) + break; + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dTemp; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei]+NC+1, + dTemp, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } + } ); + return; + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + if (1) + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + residual.zero(); + jacobian.zero(); + if( diag_check || iwelem > 0 ) + { + // here is the perturbation in the temperature of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + if ( iwelem == 1 ) + { + real64 dRdX = 0.0; + globalIndex rowIndex = wellElemDofNumber[0] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1; ; + for (integer ider=0;ider< 3;ider++ ) + { + globalIndex colIndex = wellElemDofNumber[0]+ ider; + jacobianFD.removeNonZero ( rowIndex, colIndex ); + jacobianFD.insertNonZero( rowIndex, colIndex, dRdX ); + } + jacobianFD.removeNonZero ( rowIndex, wellElemDofNumber[1]+3); + jacobianFD.insertNonZero( rowIndex, wellElemDofNumber[1]+3, dRdX); + } + } + else + { + real64 dRdX = 0.0; + globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1; ; + dRdX = 1.0; + jacobianFD.removeNonZero(rowIndex,rowIndex); + jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); + //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); + } + + } + } + + + // b) compute all the derivatives wrt to the connection in WELL elem + // iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 1 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleCouplingTerms( time,dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true , + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->computePerforationRates( time, dt, domain ); + solver->wellSolver()->assembleFluxTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +#if 1 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum_Vol_Energy_Bal ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp new file mode 100644 index 00000000000..b60232723f9 --- /dev/null +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -0,0 +1,784 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 TotalEnergies + * Copyright (c) 2019- GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +#include "unitTests/fluidFlowTests/testCompFlowUtils.hpp" + +#include "common/DataTypes.hpp" +#include "mainInterface/initialization.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" +#include "mainInterface/GeosxState.hpp" +#include "mesh/WellElementSubRegion.hpp" +#include "physicsSolvers/PhysicsSolverManager.hpp" +#include "physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" +#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" + +using namespace geos; +using namespace geos::dataRepository; +using namespace geos::constitutive; +using namespace geos::testing; + +CommandLineOptions g_commandLineOptions; + +char const * xmlInput = + R"xml( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )xml"; + + + +template< typename LAMBDA > +void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > & solver, + DomainPartition & domain, + real64 const perturbParameter, + real64 const relTol, bool diag_check, + LAMBDA && assembleFunction ) +{ + CompositionalMultiphaseWell & wellSolver = *solver.wellSolver(); + CompositionalMultiphaseFVM & flowSolver = dynamicCast< CompositionalMultiphaseFVM & >( *solver.reservoirSolver() ); + + localIndex const NC = flowSolver.numFluidComponents(); + + CRSMatrix< real64, globalIndex > const & jacobian = solver.getLocalMatrix(); + array1d< real64 > residual( jacobian.numRows() ); + DofManager const & dofManager = solver.getDofManager(); + + // assemble the analytical residual + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.move( hostMemorySpace, false ); + + // copy the analytical residual + array1d< real64 > residualOrig( residual ); + + // create the numerical jacobian + jacobian.move( hostMemorySpace ); + CRSMatrix< real64, globalIndex > jacobianFD( jacobian ); + jacobianFD.zero(); + + string const resDofKey = dofManager.getKey( wellSolver.resElementDofName() ); + string const wellDofKey = dofManager.getKey( wellSolver.wellElementDofName() ); + + // at this point we start assembling the finite-difference block by block + + //////////////////////////////////////////////// + // Step 1) Compute the terms in J_RR and J_WR // + //////////////////////////////////////////////// + if (1) + domain.forMeshBodies( [&] ( MeshBody & meshBody ) + { + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + { + std::cout << mesh.getName() << " " ; + ElementRegionManager & elemManager = mesh.getElemManager(); + std::cout << elemManager.getName() << std::endl; + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + { + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + std::cout << " " << subRegion.getName() << " " << subRegion.size() << std::endl; + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); + + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::flow::pressure >(); + pres.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & temp = + subRegion.getField< fields::flow::temperature >(); + temp.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) + { + if ( ei !=0 ) + break; + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; + + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the element + real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dTemp; + + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei]+NC+1, + dTemp, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } + } ); + return; + } ); + + ///////////////////////////////////////////////// + // Step 2) Compute the terms in J_RW and J_WW // + ///////////////////////////////////////////////// + + // loop over the wells + if (1) + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); + + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); + + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } + + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); + + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); + residual.zero(); + jacobian.zero(); + if( diag_check || iwelem > 0 ) + { + // here is the perturbation in the temperature of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + } + else + { + real64 dRdX = 0.0; + globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1; ; + dRdX = 1.0; + jacobianFD.removeNonZero(rowIndex,rowIndex); + jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); + //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); + } + + } + } + + + // b) compute all the derivatives wrt to the connection in WELL elem + // iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) + { + { + solver.resetStateToBeginningOfStep( domain ); + + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; + + wellSolver.updateState( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } + } + } ); + } ); + + // assemble the analytical jacobian + solver.resetStateToBeginningOfStep( domain ); + + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); +} + +class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test +{ +public: + + CompositionalMultiphaseReservoirSolverTest(): + state( std::make_unique< CommandLineOptions >( g_commandLineOptions ) ) + {} + +protected: + + void SetUp() override + { + setupProblemFromXML( state.getProblemManager(), xmlInput ); + solver = &state.getProblemManager().getPhysicsSolverManager().getGroup< CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > >( "reservoirSystem" ); + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + solver->setupSystem( domain, + solver->getDofManager(), + solver->getLocalMatrix(), + solver->getSystemRhs(), + solver->getSystemSolution() ); + + solver->implicitStepSetup( time, dt, domain ); + } + + static real64 constexpr time = 0.0; + static real64 constexpr dt = 1e4; + static real64 constexpr eps = std::numeric_limits< real64 >::epsilon(); + + GeosxState state; + CompositionalMultiphaseReservoirAndWells< CompositionalMultiphaseBase > * solver; +}; + +real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; +real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; + +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif + +#if 1 +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleSystem( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + //solver->assembleCouplingTerms( time,dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} + +#endif +#if 0 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_flux ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true , + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->computePerforationRates( time, dt, domain ); + solver->wellSolver()->assembleFluxTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->assembleCouplingTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +#if 1 + +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum_Vol_Energy_Bal ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, false, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_PressureRel ) +{ + real64 const perturb = std::sqrt( eps ); + real64 const tol = 1e-1; // 10% error margin + + DomainPartition & domain = state.getProblemManager().getDomainPartition(); + + testNumericalJacobian( *solver, domain, perturb, tol, true, + [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + solver->wellSolver()->assemblePressureRelations( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); + } ); +} +#endif +int main( int argc, char * * argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + g_commandLineOptions = *geos::basicSetup( argc, argv ); + int const result = RUN_ALL_TESTS(); + geos::basicCleanup(); + return result; +} From bea94d524012f74a4fc56f25f0c33750c616c219 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:39:55 -0700 Subject: [PATCH 25/71] more pedantics --- .../physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index eaa5787499e..73bf7d9a0ea 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -677,7 +677,7 @@ class PerforationFluxKernelFactory } }; -}; // end namespace isothermalPerforationFluxKernels +} // end namespace isothermalPerforationFluxKernels namespace thermalPerforationFluxKernels { From 887192da6900daa174c5e7e7d295cf2e36c92431 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:20:36 -0700 Subject: [PATCH 26/71] pedantics --- .../wells/ThermalCompositionalMultiphaseWellKernels.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index a0eef7ebbee..ae2c143a939 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -1103,7 +1103,7 @@ class FaceBasedAssemblyKernelFactory } }; -}; // end namespace thermalCompositionalMultiphaseWellKernels +} // end namespace thermalCompositionalMultiphaseWellKernels } // end namespace geos From b9b6676eca192d01e60bd1a9ec378fb6a36a3a46 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:14:46 -0700 Subject: [PATCH 27/71] remove debug --- .../testIsothermalReservoirCompositionalMultiphaseMSWells.cpp | 2 +- .../testIsothermalReservoirCompositionalMultiphaseSSWells.cpp | 2 +- .../testThermalReservoirCompositionalMultiphaseMSWells.cpp | 2 +- .../testThermalReservoirCompositionalMultiphaseSSWells.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp index c22603b903a..b924077e028 100644 --- a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp @@ -531,7 +531,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio residual.zero(); jacobian.zero(); assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); } diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp index a440c8b7c98..b8f79fa7355 100644 --- a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp @@ -603,7 +603,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio residual.zero(); jacobian.zero(); assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 1ab87fc151a..09582599948 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -656,7 +656,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio residual.zero(); jacobian.zero(); assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp index b60232723f9..00a82a3fc0b 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -643,7 +643,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio residual.zero(); jacobian.zero(); assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); + //printCompareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst()); compareLocalMatrices( jacobian.toViewConst(), jacobianFD.toViewConst(), relTol ); } From 99efdea8818329b77594b293d2d3821ee55ddbd2 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Thu, 6 Jun 2024 06:51:15 -0700 Subject: [PATCH 28/71] compiler warning error --- ...eservoirCompositionalMultiphaseSSWells.cpp | 415 +++++++++--------- 1 file changed, 208 insertions(+), 207 deletions(-) diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp index 00a82a3fc0b..cf905e59a47 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -340,150 +340,151 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio //////////////////////////////////////////////// // Step 1) Compute the terms in J_RR and J_WR // //////////////////////////////////////////////// - if (1) + if( 1 ) domain.forMeshBodies( [&] ( MeshBody & meshBody ) { meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) { - std::cout << mesh.getName() << " " ; + std::cout << mesh.getName() << " "; ElementRegionManager & elemManager = mesh.getElemManager(); - std::cout << elemManager.getName() << std::endl; + std::cout << elemManager.getName() << std::endl; for( localIndex er = 0; er < elemManager.numRegions(); ++er ) { ElementRegionBase & elemRegion = elemManager.getRegion( er ); elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) { - std::cout << " " << subRegion.getName() << " " << subRegion.size() << std::endl; + std::cout << " " << subRegion.getName() << " " << subRegion.size() << std::endl; // get the degrees of freedom and ghosting information arrayView1d< globalIndex const > const & dofNumber = subRegion.getReference< array1d< globalIndex > >( resDofKey ); // get the primary variables on the reservoir elements arrayView1d< real64 > const & pres = - subRegion.getField< fields::flow::pressure >(); + subRegion.getField< fields::flow::pressure >(); pres.move( hostMemorySpace, false ); arrayView2d< real64, compflow::USD_COMP > const & compDens = - subRegion.getField< fields::flow::globalCompDensity >(); + subRegion.getField< fields::flow::globalCompDensity >(); compDens.move( hostMemorySpace, false ); - arrayView1d< real64 > const & temp = - subRegion.getField< fields::flow::temperature >(); - temp.move( hostMemorySpace, false ); + arrayView1d< real64 > const & temp = + subRegion.getField< fields::flow::temperature >(); + temp.move( hostMemorySpace, false ); // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei for( localIndex ei = 0; ei < subRegion.size(); ++ei ) { - if ( ei !=0 ) - break; - real64 totalDensity = 0.0; - for( localIndex ic = 0; ic < NC; ++ic ) + if( ei ==0 ) { - totalDensity += compDens[ei][ic]; - } + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } - { - solver.resetStateToBeginningOfStep( domain ); + { + solver.resetStateToBeginningOfStep( domain ); - // here is the perturbation in the pressure of the element - real64 const dP = perturbParameter * (pres[ei] + perturbParameter); - pres.move( hostMemorySpace, true ); - pres[ei] += dP; + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; - // after perturbing, update the pressure-dependent quantities in the reservoir - flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh2, - arrayView1d< string const > const & regionNames2 ) - { - mesh2.getElemManager().forElementSubRegions( regionNames2, - [&]( localIndex const, - ElementSubRegionBase & subRegion2 ) + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) { - flowSolver.updateFluidState( subRegion2 ); + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); } ); - } ); - wellSolver.updateState( domain ); + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - dofNumber[ei], - dP, - jacobianFD.toViewConstSizes() ); - } + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } - for( localIndex jc = 0; jc < NC; ++jc ) - { - solver.resetStateToBeginningOfStep( domain ); + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); - real64 const dRho = perturbParameter * totalDensity; - compDens.move( hostMemorySpace, true ); - compDens[ei][jc] += dRho; + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; - flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh2, - arrayView1d< string const > const & regionNames2 ) - { - mesh2.getElemManager().forElementSubRegions( regionNames2, - [&]( localIndex const, - ElementSubRegionBase & subRegion2 ) + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) + { + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); + } ); + wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } { - flowSolver.updateFluidState( subRegion2 ); - } ); - } ); - wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - dofNumber[ei] + jc + 1, - dRho, - jacobianFD.toViewConstSizes() ); - } - { - solver.resetStateToBeginningOfStep( domain ); + solver.resetStateToBeginningOfStep( domain ); - // here is the perturbation in the pressure of the element - real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); - temp.move( hostMemorySpace, true ); - temp[ei] += dTemp; + // here is the perturbation in the pressure of the element + real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dTemp; - // after perturbing, update the pressure-dependent quantities in the reservoir - flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh2, - arrayView1d< string const > const & regionNames2 ) - { - mesh2.getElemManager().forElementSubRegions( regionNames2, - [&]( localIndex const, - ElementSubRegionBase & subRegion2 ) + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) { - flowSolver.updateFluidState( subRegion2 ); + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); } ); - } ); - wellSolver.updateState( domain ); + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - dofNumber[ei]+NC+1, - dTemp, + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei]+NC+1, + dTemp, jacobianFD.toViewConstSizes() ); } + } } } ); } } ); - return; + return; } ); ///////////////////////////////////////////////// @@ -491,151 +492,151 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio ///////////////////////////////////////////////// // loop over the wells - if (1) - wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) + if( 1 ) + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - // get the degrees of freedom, ghosting info and next well elem index - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - // get the primary variables on the well elements - arrayView1d< real64 > const & wellElemPressure = - subRegion.getField< fields::well::pressure >(); - wellElemPressure.move( hostMemorySpace, false ); + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< real64 > const & wellElemTemperature = - subRegion.getField< fields::well::temperature >(); - wellElemTemperature.move( hostMemorySpace, false ); + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = - subRegion.getField< fields::well::globalCompDensity >(); - wellElemCompDens.move( hostMemorySpace, false ); + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); - arrayView1d< real64 > const & connRate = - subRegion.getField< fields::well::mixtureConnectionRate >(); - connRate.move( hostMemorySpace, false ); + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); - // a) compute all the derivatives wrt to the pressure in WELL elem iwelem - for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) - { + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); - real64 wellElemTotalDensity = 0.0; - for( localIndex ic = 0; ic < NC; ++ic ) + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) { - wellElemTotalDensity += wellElemCompDens[iwelem][ic]; - } - { - solver.resetStateToBeginningOfStep( domain ); + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } + + { + solver.resetStateToBeginningOfStep( domain ); - // here is the perturbation in the pressure of the well element - real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); - wellElemPressure.move( hostMemorySpace, true ); - wellElemPressure[iwelem] += dP; + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; - // after perturbing, update the pressure-dependent quantities in the well - wellSolver.updateState( domain ); + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, - dP, - jacobianFD.toViewConstSizes() ); - } + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } - for( localIndex jc = 0; jc < NC; ++jc ) - { - solver.resetStateToBeginningOfStep( domain ); + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); - real64 const dRho = perturbParameter * wellElemTotalDensity; - wellElemCompDens.move( hostMemorySpace, true ); - wellElemCompDens[iwelem][jc] += dRho; + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; - wellSolver.updateState( domain ); + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, - dRho, - jacobianFD.toViewConstSizes() ); - } - { - solver.resetStateToBeginningOfStep( domain ); - residual.zero(); - jacobian.zero(); - if( diag_check || iwelem > 0 ) + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, + jacobianFD.toViewConstSizes() ); + } { - // here is the perturbation in the temperature of the well element - real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); - wellElemTemperature.move( hostMemorySpace, true ); - wellElemTemperature[iwelem] += dT; + solver.resetStateToBeginningOfStep( domain ); + residual.zero(); + jacobian.zero(); + if( diag_check || iwelem > 0 ) + { + // here is the perturbation in the temperature of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; - // after perturbing, update the pressure-dependent quantities in the well - wellSolver.updateState( domain ); + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, - dT, - jacobianFD.toViewConstSizes() ); - } - else - { - real64 dRdX = 0.0; - globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1; ; - dRdX = 1.0; - jacobianFD.removeNonZero(rowIndex,rowIndex); - jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); - //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); - } + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + } + else + { + real64 dRdX = 0.0; + globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + dRdX = 1.0; + jacobianFD.removeNonZero( rowIndex, rowIndex ); + jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); + //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); + } + } } - } - // b) compute all the derivatives wrt to the connection in WELL elem - // iwelem - for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) - { + // b) compute all the derivatives wrt to the connection in WELL elem + // iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) { - solver.resetStateToBeginningOfStep( domain ); + { + solver.resetStateToBeginningOfStep( domain ); - // here is the perturbation in the rate of the well element - real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); - connRate.move( hostMemorySpace, true ); - connRate[iwelem] += dRate; + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; - wellSolver.updateState( domain ); + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, - dRate, - jacobianFD.toViewConstSizes() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } } - } + } ); } ); - } ); // assemble the analytical jacobian solver.resetStateToBeginningOfStep( domain ); @@ -733,7 +734,7 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_flux DomainPartition & domain = state.getProblemManager().getDomainPartition(); - testNumericalJacobian( *solver, domain, perturb, tol, true , + testNumericalJacobian( *solver, domain, perturb, tol, true, [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { From 2b8ca8dabd1e2ed5c497da17345c82d779c85ebc Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Fri, 7 Jun 2024 10:53:41 -0700 Subject: [PATCH 29/71] fix file path --- .../testThermalReservoirCompositionalMultiphaseMSWells.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 09582599948..6c6558fb364 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -202,8 +202,8 @@ char const * xmlInput = phaseNames="{ gas, water }" componentNames="{ co2, water }" componentMolarWeight="{ 44e-3, 18e-3 }" - phasePVTParaFiles="{ /Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/pvtgas.txt, /Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/pvtliquid.txt }" - flashModelParaFile="/Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/co2flash.txt"/> + phasePVTParaFiles="{ ../../src/coreComponents/unitTests/wellsTests/pvtgas.txt, ../../src/coreComponents/unitTests/wellsTests/pvtliquid.txt }" + flashModelParaFile="../../src/coreComponents/unitTests/wellsTests/co2flash.txt"/> Date: Mon, 10 Jun 2024 12:19:54 -0700 Subject: [PATCH 30/71] lets try all combinations of file input path --- .../testThermalReservoirCompositionalMultiphaseMSWells.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 6c6558fb364..a48def270e6 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -202,8 +202,8 @@ char const * xmlInput = phaseNames="{ gas, water }" componentNames="{ co2, water }" componentMolarWeight="{ 44e-3, 18e-3 }" - phasePVTParaFiles="{ ../../src/coreComponents/unitTests/wellsTests/pvtgas.txt, ../../src/coreComponents/unitTests/wellsTests/pvtliquid.txt }" - flashModelParaFile="../../src/coreComponents/unitTests/wellsTests/co2flash.txt"/> + phasePVTParaFiles="{ pvtgas.txt, pvtliquid.txt }" + flashModelParaFile="co2flash.txt"/> Date: Fri, 14 Jun 2024 10:50:22 -0700 Subject: [PATCH 31/71] updated to latest dev/modules --- host-configs/apple/macOS_base.cmake | 3 +- scripts/uberenv | 1 + src/coreComponents/LvArray | 2 +- .../fileIO/coupling/hdf5_interface | 2 +- .../wells/CompositionalMultiphaseWell.cpp | 52 +------------------ .../wells/CompositionalMultiphaseWell.hpp | 6 --- .../CompositionalMultiphaseWellKernels.cpp | 4 -- .../wells/PerforationFluxKernels.hpp | 7 --- .../fluidFlow/wells/SinglePhaseWell.cpp | 25 --------- .../fluidFlow/wells/SinglePhaseWell.hpp | 6 --- .../fluidFlow/wells/WellControls.cpp | 2 - .../fluidFlow/wells/WellSolverBase.cpp | 24 +++++++++ .../fluidFlow/wells/WellSolverBase.hpp | 12 ++--- ...eservoirCompositionalMultiphaseMSWells.cpp | 4 +- ...eservoirCompositionalMultiphaseSSWells.cpp | 4 +- ...eservoirCompositionalMultiphaseMSWells.cpp | 3 -- ...eservoirCompositionalMultiphaseSSWells.cpp | 7 +-- 17 files changed, 42 insertions(+), 122 deletions(-) create mode 160000 scripts/uberenv diff --git a/host-configs/apple/macOS_base.cmake b/host-configs/apple/macOS_base.cmake index a00bc8e11d6..27a9e2779c9 100644 --- a/host-configs/apple/macOS_base.cmake +++ b/host-configs/apple/macOS_base.cmake @@ -55,5 +55,6 @@ endif() # ATS set(ATS_ARGUMENTS "--machine openmpi --ats openmpi_mpirun=${MPIEXEC}" CACHE PATH "") #set(GEOSX_TPL_DIR "/Users/byer3/GEOS-DEV/thirdPartyLibs/install-mac-debug" CACHE PATH "" FORCE) -set(GEOSX_TPL_DIR "/Users/byer3/GEOS-DEV/thirdPartyLibs/install-mac_rel-release" CACHE PATH "" FORCE) +set(GEOSX_TPL_DIR "/Users/byer3/GEOS-DEV-20240517/thirdPartyLibs/install-mac_rel-release" CACHE PATH "" FORCE) +set(GEOSX_TPL_DIR "/Users/byer3/gd_20240517/thirdPartyLibs/install-mac_rel-release" CACHE PATH "" FORCE) include(${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake) diff --git a/scripts/uberenv b/scripts/uberenv new file mode 160000 index 00000000000..d0cf52c5894 --- /dev/null +++ b/scripts/uberenv @@ -0,0 +1 @@ +Subproject commit d0cf52c58949eeb5226e7dbee8b6ac4cbea48b0c diff --git a/src/coreComponents/LvArray b/src/coreComponents/LvArray index e6b7f90c1aa..1531241583e 160000 --- a/src/coreComponents/LvArray +++ b/src/coreComponents/LvArray @@ -1 +1 @@ -Subproject commit e6b7f90c1aaa53992962ce6510dc000cc06c1943 +Subproject commit 1531241583eebe21cfcdc0facd16a80f1e03c939 diff --git a/src/coreComponents/fileIO/coupling/hdf5_interface b/src/coreComponents/fileIO/coupling/hdf5_interface index 5136554439e..7ee534586a6 160000 --- a/src/coreComponents/fileIO/coupling/hdf5_interface +++ b/src/coreComponents/fileIO/coupling/hdf5_interface @@ -1 +1 @@ -Subproject commit 5136554439e791dc5e948f2a74ede31c4c697ef5 +Subproject commit 7ee534586a6ea995532eb4e3cfc7da4e5ccff64a diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index bb013dd5a2c..a2bcb0dabb5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -851,33 +851,17 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg } + void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRegion ) { GEOS_MARK_FUNCTION; - using Deriv = multifluid::DerivativeOffset; arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >(); arrayView1d< real64 const > const & temp = subRegion.getField< fields::well::temperature >(); - arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >(); arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >(); - arrayView2d< real64 const, compflow::USD_COMP > const & pvFrac = subRegion.getField< fields::well::phaseVolumeFraction >(); - arrayView2d< real64 const, compflow::USD_COMP > const & compDens = subRegion.getField< fields::well::globalCompDensity >(); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy=fluid.phaseInternalEnergy(); - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy=fluid.dPhaseInternalEnergy(); - std::cout << subRegion.getName() << std::endl; - - for( integer i=0; i const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - string const wellDofKey = dofManager.getKey( wellElementDofName()); - - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then assemble the pressure relations between well elements - assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( time, dt, domain ); - - // then assemble the flux terms in the mass balance equations - // get a reference to the degree-of-freedom numbers - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - - -} void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update properties diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index a240c6b729b..82bc009b75a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -203,12 +203,6 @@ class CompositionalMultiphaseWell : public WellSolverBase integer useTotalMassEquation() const { return m_useTotalMassEquation; } - virtual void assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the flux terms for all connections between well elements * @param time_n previous time value diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index a01e4027361..e3236ba5b0d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -167,7 +167,6 @@ ControlEquationHelper:: if( currentControl == WellControls::Control::BHP ) { // control equation is a difference between current BHP and target BHP - std::cout << "Current control - BHP " << targetBHP << " " << currentBHP << std::endl; controlEqn = currentBHP - targetBHP; dControlEqn[COFFSET_WJ::dP] = dCurrentBHP[Deriv::dP]; for( integer ic = 0; ic < NC; ++ic ) @@ -195,9 +194,6 @@ ControlEquationHelper:: // Total volumetric rate control else if( currentControl == WellControls::Control::TOTALVOLRATE ) { - if( targetTotalRate <= 0.0 ) - std::cout << "Shutin " << std::endl; - std::cout << "Current control - TOTALVOLRATE " << targetTotalRate << " " << currentTotalVolRate << std::endl; controlEqn = currentTotalVolRate - targetTotalRate; dControlEqn[COFFSET_WJ::dP] = dCurrentTotalVolRate[COFFSET_WJ::dP]; dControlEqn[COFFSET_WJ::dQ] = dCurrentTotalVolRate[COFFSET_WJ::dQ]; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index 73bf7d9a0ea..c533bf3f45d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -222,8 +222,6 @@ class PerforationFluxKernel // b) get well variables pres[TAG::WELL] = m_wellElemPres[iwelem]; - std::cout << "wrpres " << iwelem << " RES " << pres[TAG::RES] << " WELL " << pres[TAG::WELL] - << " dp " << pres[TAG::WELL]-pres[TAG::RES]; dPres[TAG::WELL][CP_Deriv::dP] = 1.0; multiplier[TAG::WELL] = -1.0; @@ -253,11 +251,6 @@ class PerforationFluxKernel dPotDiff[i][ic] += multiplier[i] * m_perfTrans[iperf] * dPres[i][ic]; } } - std::cout << " WELLC " << pres[TAG::WELL] << " dp " << pres[TAG::WELL]-pres[TAG::RES] << - " " << m_wellElemCompDens[iwelem][0] << " " << m_wellElemCompDens[iwelem][1] << " " - << m_wellElemCompFrac[iwelem][0] << " " << m_wellElemCompFrac[iwelem][1]; - std::cout << " potdiff " << potDiff << std::endl; - // Step 4: upwinding based on the flow direction real64 flux = 0.0; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 665c2d69114..50859c4fde0 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -481,31 +481,6 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & } ); } -void SinglePhaseWell::assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - GEOS_MARK_FUNCTION; - // assemble the accumulation term in the mass balance equations - assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then assemble the pressure relations between well elements - assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); - - // then compute the perforation rates (later assembled by the coupled solver) - computePerforationRates( time, dt, domain ); - - // then assemble the flux terms in the mass balance equations - assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); - - - // then apply a special treatment to the wells that are shut - //shutDownWell( time, dt, domain, dofManager, localMatrix, localRhs ); -} - void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, real64 const & dt, DomainPartition & domain, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 2d41dbd9bc3..a9c0177885f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -168,12 +168,6 @@ class SinglePhaseWell : public WellSolverBase */ virtual void updateSubRegionState( WellElementSubRegion & subRegion ) override; - virtual void assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the flux terms for all connections between well elements * @param time_n previous time value diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp index 0089c95c099..4d97682591b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp @@ -172,14 +172,12 @@ void WellControls::switchToBHPControl( real64 const & val ) { m_currentControl = Control::BHP; m_targetBHP = val; - std::cout << "Control BHP " << val << std::endl; } void WellControls::switchToTotalRateControl( real64 const & val ) { m_currentControl = Control::TOTALVOLRATE; m_targetTotalRate = val; - std::cout << "Control TOTALVOLRATE " << val << std::endl; } void WellControls::switchToPhaseRateControl( real64 const & val ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 9e5b41b77c1..68733df48a5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -256,6 +256,30 @@ void WellSolverBase::updateState( DomainPartition & domain ) } ); } +void WellSolverBase::assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + string const wellDofKey = dofManager.getKey( wellElementDofName()); + + // assemble the accumulation term in the mass balance equations + assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs ); + + // then assemble the pressure relations between well elements + assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs ); + // then compute the perforation rates (later assembled by the coupled solver) + computePerforationRates( time, dt, domain ); + + // then assemble the flux terms in the mass balance equations + // get a reference to the degree-of-freedom numbers + // then assemble the flux terms in the mass balance equations + assembleFluxTerms( time, dt, domain, dofManager, localMatrix, localRhs ); + +} + void WellSolverBase::initializePostInitialConditionsPreSubGroups() { SolverBase::initializePostInitialConditionsPreSubGroups(); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index b4db2d678f4..879babf5909 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -180,12 +180,12 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleSystem( real64 const GEOS_UNUSED_PARAM( time ), - real64 const GEOS_UNUSED_PARAM( dt ), - DomainPartition & GEOS_UNUSED_PARAM( domain ), - DofManager const & GEOS_UNUSED_PARAM( dofManager ), - CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), - arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) override {}; + virtual void assembleSystem( real64 const time , + real64 const dt , + DomainPartition & domain , + DofManager const & dofManager , + CRSMatrixView< real64, globalIndex const > const & localMatrix , + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the flux terms for all connections between well elements diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp index b924077e028..3909a24cd76 100644 --- a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp @@ -193,8 +193,8 @@ char const * xmlInput = phaseNames="{ gas, water }" componentNames="{ co2, water }" componentMolarWeight="{ 44e-3, 18e-3 }" - phasePVTParaFiles="{ /Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/pvtgas.txt, /Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/pvtliquid.txt }" - flashModelParaFile="/Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/co2flash.txt"/> + phasePVTParaFiles="{ pvtgas.txt, pvtliquid.txt }" + flashModelParaFile="co2flash.txt"/> + phasePVTParaFiles="{ pvtgas.txt, pvtliquid.txt }" + flashModelParaFile="co2flash.txt"/> ( [&]( localIndex const, CellElementSubRegion & subRegion ) { - std::cout << " " << subRegion.getName() << " " << subRegion.size() << std::endl; // get the degrees of freedom and ghosting information arrayView1d< globalIndex const > const & dofNumber = subRegion.getReference< array1d< globalIndex > >( resDofKey ); diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp index cf905e59a47..bd6ee39cacf 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -202,8 +202,8 @@ char const * xmlInput = phaseNames="{ gas, water }" componentNames="{ co2, water }" componentMolarWeight="{ 44e-3, 18e-3 }" - phasePVTParaFiles="{ /Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/pvtgas.txt, /Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/pvtliquid.txt }" - flashModelParaFile="/Users/byer3/GEOS-DEV/mass_inj_const/src/coreComponents/unitTests/wellsTests/co2flash.txt"/> + phasePVTParaFiles="{ pvtgas.txt, pvtliquid.txt }" + flashModelParaFile="co2flash.txt"/> ( [&]( localIndex const, CellElementSubRegion & subRegion ) { - std::cout << " " << subRegion.getName() << " " << subRegion.size() << std::endl; // get the degrees of freedom and ghosting information arrayView1d< globalIndex const > const & dofNumber = subRegion.getReference< array1d< globalIndex > >( resDofKey ); From 0e2b420fa144fd9105fffbf6656f4cf71f82962f Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Fri, 14 Jun 2024 11:22:01 -0700 Subject: [PATCH 32/71] cleanup --- .../wells/CompositionalMultiphaseWell.cpp | 277 ++++------- .../wells/CompositionalMultiphaseWell.hpp | 8 - ...rmalCompositionalMultiphaseWellKernels.hpp | 4 +- .../fluidFlow/wells/WellSolverBase.cpp | 10 +- .../fluidFlow/wells/WellSolverBase.hpp | 12 +- ...eservoirCompositionalMultiphaseMSWells.cpp | 470 +++++++++--------- 6 files changed, 333 insertions(+), 448 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index a2bcb0dabb5..95de4386092 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1220,11 +1220,11 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time real64 -CompositionalMultiphaseWell::calculateResidualNorm1( real64 const & time_n, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ) +CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, + real64 const & dt, + DomainPartition const & domain, + DofManager const & dofManager, + arrayView1d< real64 const > const & localRhs ) { GEOS_MARK_FUNCTION; @@ -1346,79 +1346,7 @@ CompositionalMultiphaseWell::calculateResidualNorm1( real64 const & time_n, } return resNorm; } -real64 -CompositionalMultiphaseWell::calculateResidualNorm( real64 const & time_n, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ) -{ - - return calculateResidualNorm1( time_n, dt, domain, dofManager, localRhs ); - - GEOS_MARK_FUNCTION; - - real64 localResidualNorm = 0.0; - - globalIndex const rankOffset = dofManager.rankOffset(); - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - - - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - real64 subRegionResidualNorm[1]{}; - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - - WellControls const & wellControls = getWellControls( subRegion ); - - // step 1: compute the norm in the subRegion - - ResidualNormKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_numComponents, - numDofPerWellElement(), - m_targetPhaseIndex, - rankOffset, - wellDofKey, - localRhs, - subRegion, - fluid, - wellControls, - time_n + dt, - dt, - m_nonlinearSolverParameters.m_minNormalizer, - subRegionResidualNorm ); - - // step 2: reduction across meshBodies/regions/subRegions - - if( subRegionResidualNorm[0] > localResidualNorm ) - { - localResidualNorm = subRegionResidualNorm[0]; - } - - } ); - } ); - - // step 3: second reduction across MPI ranks - - real64 const residualNorm = MpiWrapper::max( localResidualNorm ); - - if( getLogLevel() >= 1 && logger::internal::rank == 0 ) - { - std::cout << GEOS_FMT( " ( R{} ) = ( {:4.2e} )", coupledSolverAttributePrefix(), residualNorm ); - } - return residualNorm; -} real64 CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, DofManager const & dofManager, @@ -1429,134 +1357,102 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, string const wellDofKey = dofManager.getKey( wellElementDofName() ); real64 scalingFactor = 1.0; - if( 0 ) - { - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< ElementSubRegionBase >( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) - { - // check that pressure and component densities are non-negative - auto const subRegionData = - compositionalMultiphaseWellKernels:: - ScalingForSystemSolutionKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, - m_maxAbsolutePresChange, - m_maxCompFracChange, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution ); + real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0; + real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0; - scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); - } ); - - } ); - - return LvArray::math::max( MpiWrapper::min( scalingFactor ), m_minScalingFactor ); - } - else + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0; - real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0; - - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) + mesh.getElemManager().forElementSubRegions( regionNames, + [&]( localIndex const, + ElementSubRegionBase & subRegion ) { - mesh.getElemManager().forElementSubRegions( regionNames, - [&]( localIndex const, - ElementSubRegionBase & subRegion ) - { - arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); - arrayView1d< real64 const > const temperature = subRegion.getField< fields::well::temperature >(); - arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >(); - arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); - arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); - arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); - const integer temperatureOffset = m_numComponents+2; - auto const subRegionData = - m_isThermal + arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 const > const temperature = subRegion.getField< fields::well::temperature >(); + arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >(); + arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >(); + arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >(); + arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); + const integer temperatureOffset = m_numComponents+2; + auto const subRegionData = + m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, - m_maxAbsolutePresChange, - m_maxRelativeTempChange, - m_maxCompFracChange, - pressure, - temperature, - compDens, - pressureScalingFactor, - compDensScalingFactor, - temperatureScalingFactor, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution, - temperatureOffset ) + ScalingForSystemSolutionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, + m_maxAbsolutePresChange, + m_maxRelativeTempChange, + m_maxCompFracChange, + pressure, + temperature, + compDens, + pressureScalingFactor, + compDensScalingFactor, + temperatureScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution, + temperatureOffset ) : isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, - m_maxAbsolutePresChange, - m_maxCompFracChange, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor, - dofManager.rankOffset(), - m_numComponents, - wellDofKey, - subRegion, - localSolution ); + ScalingForSystemSolutionKernelFactory:: + createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, + m_maxAbsolutePresChange, + m_maxCompFracChange, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor, + dofManager.rankOffset(), + m_numComponents, + wellDofKey, + subRegion, + localSolution ); - scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); + scalingFactor = std::min( subRegionData.localMinVal, scalingFactor ); - maxDeltaPres = std::max( maxDeltaPres, subRegionData.localMaxDeltaPres ); - maxDeltaCompDens = std::max( maxDeltaCompDens, subRegionData.localMaxDeltaCompDens ); - maxDeltaTemp = std::max( maxDeltaTemp, subRegionData.localMaxDeltaTemp ); - minPresScalingFactor = std::min( minPresScalingFactor, subRegionData.localMinPresScalingFactor ); - minCompDensScalingFactor = std::min( minCompDensScalingFactor, subRegionData.localMinCompDensScalingFactor ); - minTempScalingFactor = std::min( minTempScalingFactor, subRegionData.localMinTempScalingFactor ); - } ); + maxDeltaPres = std::max( maxDeltaPres, subRegionData.localMaxDeltaPres ); + maxDeltaCompDens = std::max( maxDeltaCompDens, subRegionData.localMaxDeltaCompDens ); + maxDeltaTemp = std::max( maxDeltaTemp, subRegionData.localMaxDeltaTemp ); + minPresScalingFactor = std::min( minPresScalingFactor, subRegionData.localMinPresScalingFactor ); + minCompDensScalingFactor = std::min( minCompDensScalingFactor, subRegionData.localMinCompDensScalingFactor ); + minTempScalingFactor = std::min( minTempScalingFactor, subRegionData.localMinTempScalingFactor ); } ); + } ); - scalingFactor = MpiWrapper::min( scalingFactor ); - maxDeltaPres = MpiWrapper::max( maxDeltaPres ); - maxDeltaCompDens = MpiWrapper::max( maxDeltaCompDens ); - minPresScalingFactor = MpiWrapper::min( minPresScalingFactor ); - minCompDensScalingFactor = MpiWrapper::min( minCompDensScalingFactor ); + scalingFactor = MpiWrapper::min( scalingFactor ); + maxDeltaPres = MpiWrapper::max( maxDeltaPres ); + maxDeltaCompDens = MpiWrapper::max( maxDeltaCompDens ); + minPresScalingFactor = MpiWrapper::min( minPresScalingFactor ); + minCompDensScalingFactor = MpiWrapper::min( minCompDensScalingFactor ); - string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well pressure change: {} Pa (before scaling)", - getName(), GEOS_FMT( "{:.{}f}", maxDeltaPres, 3 ) ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well component density change: {} {} (before scaling)", - getName(), GEOS_FMT( "{:.{}f}", maxDeltaCompDens, 3 ), massUnit ) ); + string const massUnit = m_useMass ? "kg/m3" : "mol/m3"; + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well pressure change: {} Pa (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaPres, 3 ) ) ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well component density change: {} {} (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaCompDens, 3 ), massUnit ) ); - if( m_isThermal ) - { - maxDeltaTemp = MpiWrapper::max( maxDeltaTemp ); - minTempScalingFactor = MpiWrapper::min( minTempScalingFactor ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well temperature change: {} K (before scaling)", - getName(), GEOS_FMT( "{:.{}f}", maxDeltaTemp, 3 ) ) ); - } + if( m_isThermal ) + { + maxDeltaTemp = MpiWrapper::max( maxDeltaTemp ); + minTempScalingFactor = MpiWrapper::min( minTempScalingFactor ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well temperature change: {} K (before scaling)", + getName(), GEOS_FMT( "{:.{}f}", maxDeltaTemp, 3 ) ) ); + } - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well pressure scaling factor: {}", getName(), minPresScalingFactor ) ); - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well component density scaling factor: {}", getName(), minCompDensScalingFactor ) ); - if( m_isThermal ) - { - GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well temperature scaling factor: {}", getName(), minTempScalingFactor ) ); - } + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well pressure scaling factor: {}", getName(), minPresScalingFactor ) ); + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well component density scaling factor: {}", getName(), minCompDensScalingFactor ) ); + if( m_isThermal ) + { + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Min well temperature scaling factor: {}", getName(), minTempScalingFactor ) ); + } - return LvArray::math::max( scalingFactor, m_minScalingFactor ); - } + return LvArray::math::max( scalingFactor, m_minScalingFactor ); + } bool @@ -1796,21 +1692,18 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager, fields::well::pressure::key(), scalingFactor, pressureMask ); - //{ m_numDofPerWellElement, 0, 1 } ); dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::globalCompDensity::key(), scalingFactor, componentMask ); - //{ m_numDofPerWellElement, 1, m_numDofPerWellElement - 1 } ); dofManager.addVectorToField( localSolution, wellElementDofName(), fields::well::mixtureConnectionRate::key(), scalingFactor, connRateMask ); - //{ m_numDofPerWellElement, m_numDofPerWellElement - 1, m_numDofPerWellElement } ); if( isThermal() ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 82bc009b75a..dfa23de36f8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -92,14 +92,6 @@ class CompositionalMultiphaseWell : public WellSolverBase /**@{*/ - virtual real64 - calculateResidualNorm1( real64 const & time_n, - real64 const & dt, - DomainPartition const & domain, - DofManager const & dofManager, - arrayView1d< real64 const > const & localRhs ); - - virtual real64 calculateResidualNorm( real64 const & time_n, real64 const & dt, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index ae2c143a939..2b56b09b54d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -991,9 +991,9 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB for( integer dof=0; dof < numComp; dof++ ) { stack.localEnergyFluxJacobian[TAG::NEXT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] - +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; + +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; stack.localEnergyFluxJacobian[TAG::CURRENT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof] - +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; + +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip]; } } stack.localEnergyFlux[TAG::NEXT ] = m_dt * eflux * currentConnRate; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 68733df48a5..e62237b949e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -257,11 +257,11 @@ void WellSolverBase::updateState( DomainPartition & domain ) } void WellSolverBase::assembleSystem( real64 const time, - real64 const dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) { string const wellDofKey = dofManager.getKey( wellElementDofName()); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 879babf5909..3e0d5008739 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -180,12 +180,12 @@ class WellSolverBase : public SolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - virtual void assembleSystem( real64 const time , - real64 const dt , - DomainPartition & domain , - DofManager const & dofManager , - CRSMatrixView< real64, globalIndex const > const & localMatrix , - arrayView1d< real64 > const & localRhs ) override; + virtual void assembleSystem( real64 const time, + real64 const dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the flux terms for all connections between well elements diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 8d34acacca4..2a6833f3445 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -340,312 +340,312 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio //////////////////////////////////////////////// // Step 1) Compute the terms in J_RR and J_WR // //////////////////////////////////////////////// - if (1) - domain.forMeshBodies( [&] ( MeshBody & meshBody ) - { - meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) + if( 1 ) + domain.forMeshBodies( [&] ( MeshBody & meshBody ) { - ElementRegionManager & elemManager = mesh.getElemManager(); - for( localIndex er = 0; er < elemManager.numRegions(); ++er ) + meshBody.forMeshLevels( [&] ( MeshLevel & mesh ) { - ElementRegionBase & elemRegion = elemManager.getRegion( er ); - elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + ElementRegionManager & elemManager = mesh.getElemManager(); + for( localIndex er = 0; er < elemManager.numRegions(); ++er ) { - // get the degrees of freedom and ghosting information - arrayView1d< globalIndex const > const & dofNumber = - subRegion.getReference< array1d< globalIndex > >( resDofKey ); + ElementRegionBase & elemRegion = elemManager.getRegion( er ); + elemRegion.forElementSubRegionsIndex< CellElementSubRegion >( [&]( localIndex const, CellElementSubRegion & subRegion ) + { + // get the degrees of freedom and ghosting information + arrayView1d< globalIndex const > const & dofNumber = + subRegion.getReference< array1d< globalIndex > >( resDofKey ); - // get the primary variables on the reservoir elements - arrayView1d< real64 > const & pres = - subRegion.getField< fields::flow::pressure >(); - pres.move( hostMemorySpace, false ); + // get the primary variables on the reservoir elements + arrayView1d< real64 > const & pres = + subRegion.getField< fields::flow::pressure >(); + pres.move( hostMemorySpace, false ); - arrayView2d< real64, compflow::USD_COMP > const & compDens = - subRegion.getField< fields::flow::globalCompDensity >(); - compDens.move( hostMemorySpace, false ); + arrayView2d< real64, compflow::USD_COMP > const & compDens = + subRegion.getField< fields::flow::globalCompDensity >(); + compDens.move( hostMemorySpace, false ); - arrayView1d< real64 > const & temp = - subRegion.getField< fields::flow::temperature >(); - temp.move( hostMemorySpace, false ); + arrayView1d< real64 > const & temp = + subRegion.getField< fields::flow::temperature >(); + temp.move( hostMemorySpace, false ); - // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei - for( localIndex ei = 0; ei < subRegion.size(); ++ei ) - { - if ( ei !=0 ) - break; - real64 totalDensity = 0.0; - for( localIndex ic = 0; ic < NC; ++ic ) + // a) compute all the derivatives wrt to the pressure in RESERVOIR elem ei + for( localIndex ei = 0; ei < subRegion.size(); ++ei ) { - totalDensity += compDens[ei][ic]; - } + if( ei !=0 ) + break; + real64 totalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + totalDensity += compDens[ei][ic]; + } - { - solver.resetStateToBeginningOfStep( domain ); + { + solver.resetStateToBeginningOfStep( domain ); - // here is the perturbation in the pressure of the element - real64 const dP = perturbParameter * (pres[ei] + perturbParameter); - pres.move( hostMemorySpace, true ); - pres[ei] += dP; + // here is the perturbation in the pressure of the element + real64 const dP = perturbParameter * (pres[ei] + perturbParameter); + pres.move( hostMemorySpace, true ); + pres[ei] += dP; - // after perturbing, update the pressure-dependent quantities in the reservoir - flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh2, - arrayView1d< string const > const & regionNames2 ) - { - mesh2.getElemManager().forElementSubRegions( regionNames2, - [&]( localIndex const, - ElementSubRegionBase & subRegion2 ) + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) { - flowSolver.updateFluidState( subRegion2 ); + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); } ); - } ); - wellSolver.updateState( domain ); + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - dofNumber[ei], - dP, - jacobianFD.toViewConstSizes() ); - } + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei], + dP, + jacobianFD.toViewConstSizes() ); + } - for( localIndex jc = 0; jc < NC; ++jc ) - { - solver.resetStateToBeginningOfStep( domain ); + for( localIndex jc = 0; jc < NC; ++jc ) + { + solver.resetStateToBeginningOfStep( domain ); - real64 const dRho = perturbParameter * totalDensity; - compDens.move( hostMemorySpace, true ); - compDens[ei][jc] += dRho; + real64 const dRho = perturbParameter * totalDensity; + compDens.move( hostMemorySpace, true ); + compDens[ei][jc] += dRho; - flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh2, - arrayView1d< string const > const & regionNames2 ) - { - mesh2.getElemManager().forElementSubRegions( regionNames2, - [&]( localIndex const, - ElementSubRegionBase & subRegion2 ) + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) { - flowSolver.updateFluidState( subRegion2 ); + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); } ); - } ); - wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - dofNumber[ei] + jc + 1, - dRho, - jacobianFD.toViewConstSizes() ); - } - { - solver.resetStateToBeginningOfStep( domain ); + wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei] + jc + 1, + dRho, + jacobianFD.toViewConstSizes() ); + } + { + solver.resetStateToBeginningOfStep( domain ); - // here is the perturbation in the pressure of the element - real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); - temp.move( hostMemorySpace, true ); - temp[ei] += dTemp; + // here is the perturbation in the pressure of the element + real64 const dTemp = perturbParameter * (temp[ei] + perturbParameter); + temp.move( hostMemorySpace, true ); + temp[ei] += dTemp; - // after perturbing, update the pressure-dependent quantities in the reservoir - flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh2, - arrayView1d< string const > const & regionNames2 ) - { - mesh2.getElemManager().forElementSubRegions( regionNames2, - [&]( localIndex const, - ElementSubRegionBase & subRegion2 ) + // after perturbing, update the pressure-dependent quantities in the reservoir + flowSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh2, + arrayView1d< string const > const & regionNames2 ) { - flowSolver.updateFluidState( subRegion2 ); + mesh2.getElemManager().forElementSubRegions( regionNames2, + [&]( localIndex const, + ElementSubRegionBase & subRegion2 ) + { + flowSolver.updateFluidState( subRegion2 ); + } ); } ); - } ); - wellSolver.updateState( domain ); + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - dofNumber[ei]+NC+1, - dTemp, - jacobianFD.toViewConstSizes() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + dofNumber[ei]+NC+1, + dTemp, + jacobianFD.toViewConstSizes() ); + } } - } - } ); - } + } ); + } + } ); + return; } ); - return; - } ); ///////////////////////////////////////////////// // Step 2) Compute the terms in J_RW and J_WW // ///////////////////////////////////////////////// - + // loop over the wells - if (1) - wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion & subRegion ) + if( 1 ) + wellSolver.forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) { - // get the degrees of freedom, ghosting info and next well elem index - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - - // get the primary variables on the well elements - arrayView1d< real64 > const & wellElemPressure = - subRegion.getField< fields::well::pressure >(); - wellElemPressure.move( hostMemorySpace, false ); - - arrayView1d< real64 > const & wellElemTemperature = - subRegion.getField< fields::well::temperature >(); - wellElemTemperature.move( hostMemorySpace, false ); + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + // get the degrees of freedom, ghosting info and next well elem index + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = - subRegion.getField< fields::well::globalCompDensity >(); - wellElemCompDens.move( hostMemorySpace, false ); + // get the primary variables on the well elements + arrayView1d< real64 > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + wellElemPressure.move( hostMemorySpace, false ); - arrayView1d< real64 > const & connRate = - subRegion.getField< fields::well::mixtureConnectionRate >(); - connRate.move( hostMemorySpace, false ); + arrayView1d< real64 > const & wellElemTemperature = + subRegion.getField< fields::well::temperature >(); + wellElemTemperature.move( hostMemorySpace, false ); - // a) compute all the derivatives wrt to the pressure in WELL elem iwelem - for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) - { + arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = + subRegion.getField< fields::well::globalCompDensity >(); + wellElemCompDens.move( hostMemorySpace, false ); - real64 wellElemTotalDensity = 0.0; - for( localIndex ic = 0; ic < NC; ++ic ) - { - wellElemTotalDensity += wellElemCompDens[iwelem][ic]; - } + arrayView1d< real64 > const & connRate = + subRegion.getField< fields::well::mixtureConnectionRate >(); + connRate.move( hostMemorySpace, false ); + // a) compute all the derivatives wrt to the pressure in WELL elem iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) { - solver.resetStateToBeginningOfStep( domain ); - - // here is the perturbation in the pressure of the well element - real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); - wellElemPressure.move( hostMemorySpace, true ); - wellElemPressure[iwelem] += dP; - // after perturbing, update the pressure-dependent quantities in the well - wellSolver.updateState( domain ); - - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + real64 wellElemTotalDensity = 0.0; + for( localIndex ic = 0; ic < NC; ++ic ) + { + wellElemTotalDensity += wellElemCompDens[iwelem][ic]; + } - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, - dP, - jacobianFD.toViewConstSizes() ); - } + { + solver.resetStateToBeginningOfStep( domain ); - for( localIndex jc = 0; jc < NC; ++jc ) - { - solver.resetStateToBeginningOfStep( domain ); + // here is the perturbation in the pressure of the well element + real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter ); + wellElemPressure.move( hostMemorySpace, true ); + wellElemPressure[iwelem] += dP; - real64 const dRho = perturbParameter * wellElemTotalDensity; - wellElemCompDens.move( hostMemorySpace, true ); - wellElemCompDens[iwelem][jc] += dRho; + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); - wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DPRES, + dP, + jacobianFD.toViewConstSizes() ); + } - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, - dRho, - jacobianFD.toViewConstSizes() ); - } - { - solver.resetStateToBeginningOfStep( domain ); - residual.zero(); - jacobian.zero(); - if( diag_check || iwelem > 0 ) + for( localIndex jc = 0; jc < NC; ++jc ) { - // here is the perturbation in the temperature of the well element - real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); - wellElemTemperature.move( hostMemorySpace, true ); - wellElemTemperature[iwelem] += dT; + solver.resetStateToBeginningOfStep( domain ); - // after perturbing, update the pressure-dependent quantities in the well - wellSolver.updateState( domain ); + real64 const dRho = perturbParameter * wellElemTotalDensity; + wellElemCompDens.move( hostMemorySpace, true ); + wellElemCompDens[iwelem][jc] += dRho; + wellSolver.updateState( domain ); + residual.zero(); + jacobian.zero(); assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, - dT, + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + jc, + dRho, jacobianFD.toViewConstSizes() ); - if ( iwelem == 1 ) + } + { + solver.resetStateToBeginningOfStep( domain ); + residual.zero(); + jacobian.zero(); + if( diag_check || iwelem > 0 ) { - real64 dRdX = 0.0; - globalIndex rowIndex = wellElemDofNumber[0] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1; ; - for (integer ider=0;ider< 3;ider++ ) + // here is the perturbation in the temperature of the well element + real64 const dT = perturbParameter * ( wellElemTemperature[iwelem] + perturbParameter ); + wellElemTemperature.move( hostMemorySpace, true ); + wellElemTemperature[iwelem] += dT; + + // after perturbing, update the pressure-dependent quantities in the well + wellSolver.updateState( domain ); + + + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1, + dT, + jacobianFD.toViewConstSizes() ); + if( iwelem == 1 ) { - globalIndex colIndex = wellElemDofNumber[0]+ ider; - jacobianFD.removeNonZero ( rowIndex, colIndex ); - jacobianFD.insertNonZero( rowIndex, colIndex, dRdX ); + real64 dRdX = 0.0; + globalIndex rowIndex = wellElemDofNumber[0] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + for( integer ider=0; ider< 3; ider++ ) + { + globalIndex colIndex = wellElemDofNumber[0]+ ider; + jacobianFD.removeNonZero ( rowIndex, colIndex ); + jacobianFD.insertNonZero( rowIndex, colIndex, dRdX ); + } + jacobianFD.removeNonZero ( rowIndex, wellElemDofNumber[1]+3 ); + jacobianFD.insertNonZero( rowIndex, wellElemDofNumber[1]+3, dRdX ); } - jacobianFD.removeNonZero ( rowIndex, wellElemDofNumber[1]+3); - jacobianFD.insertNonZero( rowIndex, wellElemDofNumber[1]+3, dRdX); } - } - else - { - real64 dRdX = 0.0; - globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1; ; - dRdX = 1.0; - jacobianFD.removeNonZero(rowIndex,rowIndex); - jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); - //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); - } + else + { + real64 dRdX = 0.0; + globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + dRdX = 1.0; + jacobianFD.removeNonZero( rowIndex, rowIndex ); + jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); + //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); + } + } } - } - // b) compute all the derivatives wrt to the connection in WELL elem - // iwelem - for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) - { + // b) compute all the derivatives wrt to the connection in WELL elem + // iwelem + for( localIndex iwelem = 0; iwelem < subRegion.size(); ++iwelem ) { - solver.resetStateToBeginningOfStep( domain ); + { + solver.resetStateToBeginningOfStep( domain ); - // here is the perturbation in the rate of the well element - real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); - connRate.move( hostMemorySpace, true ); - connRate[iwelem] += dRate; + // here is the perturbation in the rate of the well element + real64 const dRate = perturbParameter * ( connRate[iwelem] + perturbParameter ); + connRate.move( hostMemorySpace, true ); + connRate[iwelem] += dRate; - wellSolver.updateState( domain ); + wellSolver.updateState( domain ); - residual.zero(); - jacobian.zero(); - assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); + residual.zero(); + jacobian.zero(); + assembleFunction( jacobian.toViewConstSizes(), residual.toView() ); - fillNumericalJacobian( residual.toViewConst(), - residualOrig.toViewConst(), - wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, - dRate, - jacobianFD.toViewConstSizes() ); + fillNumericalJacobian( residual.toViewConst(), + residualOrig.toViewConst(), + wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC, + dRate, + jacobianFD.toViewConstSizes() ); + } } - } + } ); } ); - } ); // assemble the analytical jacobian solver.resetStateToBeginningOfStep( domain ); @@ -743,7 +743,7 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_flux DomainPartition & domain = state.getProblemManager().getDomainPartition(); - testNumericalJacobian( *solver, domain, perturb, tol, true , + testNumericalJacobian( *solver, domain, perturb, tol, true, [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { From 11e6056971d89e1ae6abec01870106f4753b6cb2 Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Fri, 14 Jun 2024 13:03:44 -0700 Subject: [PATCH 33/71] mod fix --- .gitmodules | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitmodules b/.gitmodules index 5552178f5ce..0ce1e5d5084 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,7 @@ [submodule "src/coreComponents/fileIO/coupling/hdf5_interface"] path = src/coreComponents/fileIO/coupling/hdf5_interface url = ../../GEOS-DEV/hdf5_interface.git +[submodule "scripts/uberenv"] + path = scripts/uberenv + url = ../../LLNL/uberenv.git + From dfaa419a52ac64a52fd2b2b691faf42bc086c95f Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Fri, 14 Jun 2024 13:44:03 -0700 Subject: [PATCH 34/71] Fix runner build errors --- ...rmalCompositionalMultiphaseWellKernels.hpp | 4 +- .../wells/WellElementKernelUtilities.hpp | 283 ------------------ 2 files changed, 2 insertions(+), 285 deletions(-) delete mode 100644 src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 2b56b09b54d..02fa75f9c69 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -998,8 +998,8 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB } stack.localEnergyFlux[TAG::NEXT ] = m_dt * eflux * currentConnRate; stack.localEnergyFlux[TAG::CURRENT ] = -m_dt * eflux * currentConnRate; - stack.localEnergyFluxJacobian_dQ [TAG::NEXT ][0] = m_dt * eflux; - stack.localEnergyFluxJacobian_dQ [TAG::CURRENT][0] = -m_dt * eflux; + stack.localEnergyFluxJacobian_dQ [TAG::NEXT ][0] = m_dt * eflux_dq; + stack.localEnergyFluxJacobian_dQ [TAG::CURRENT][0] = -m_dt * eflux_dq; for( integer dof=0; dof < CP_Deriv::nDer; dof++ ) { stack.localEnergyFluxJacobian[TAG::NEXT ][dof] *= m_dt*currentConnRate; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp deleted file mode 100644 index 1a66971eed2..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellElementKernelUtilities.hpp +++ /dev/null @@ -1,283 +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 TotalEnergies - * Copyright (c) 2019- GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file WellElementKernellUtilities.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLELEMENTKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLELEMENTKERNELS_HPP - -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "constitutive/fluid/multifluid/Layouts.hpp" -#include "constitutive/capillaryPressure/layouts.hpp" - - - -namespace geos -{ - -namespace wellElementKernelUtilities -{ - -// TODO make input parameter -static constexpr real64 epsC1PPU = 5000; - - -using Deriv = constitutive::multifluid::DerivativeOffset; - -struct PotGrad -{ - template< integer NC, integer ISTHERMAL > - GEOS_HOST_DEVICE - static void - compute ( real64 const & gravCoef, - real64 const & gravCoefNext, - real64 const & pres, - real64 const & presNext, - real64 const & totalMassDens, - real64 const & totalMassDensNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, - real64 & potDiff, - real64 ( & dPotDiff)[2][NC+1+IS_THERMAL] ) - - { - // local working variables and arrays - real64 pres[2]{}; - real64 dPres_dP[2]{}; - real64 dPres_dC[2][NC]{}; - real64 dFlux_dP[2]{}; - real64 dFlux_dC[2][NC]{}; - real64 dMult_dP[2]{}; - real64 dMult_dC[2][NC]{}; - real64 dPotDiff_dP[2]{}; - real64 dPotDiff_dC[2][NC]{}; - - real64 multiplier[2]{}; - multiplier[ElemTag::CURRENT] = 1.0; - multiplier[ElemTag::NEXT] = -1.0; - - pres[ElemTag::CURRENT] = pres; - pres[ElemTag::NEXT] = presNext; - - - // local working variables and arrays - real64 dAvgMassDens_dCompCurrent[NC]{}; - real64 dAvgMassDens_dCompNext[NC]{}; - - // compute the average density at the interface between well elements - real64 const avgMassDens = 0.5 * ( totalMassDensNext + totalMassDens ); - - real64 const gravD = gravCoefNext - gravCoef; - pres[0] += - - real64 const dAvgMassDens_dPresNext = 0.5 * dTotalMassDensNext[Deriv::dP]; - real64 const dAvgMassDens_dPresCurrent = 0.5 * dTotalMassDens[Deriv::dP]; - for( integer ic = 0; ic < NC; ++ic ) - { - dAvgMassDens_dCompNext[ic] = 0.5 * dTotalMassDensNext[Deriv::dC+ic]; - dAvgMassDens_dCompCurrent[ic] = 0.5 * dTotalMassDens[Deriv::dC+ic]; - } - - // compute depth diff times acceleration - real64 const gravD = gravCoefNext - gravCoef; - - potDiff = presNext - pres - avgMassDens * gravD; - - // TODO: add friction and acceleration terms - - /* - localPresRel = ( presNext - pres - avgMassDens * gravD ); - dpot_dp_next = ( 1 - dAvgMassDens_dPresNext * gravD ); - dpot_dp_cur = ( -1 - dAvgMassDens_dPresCurrent * gravD ); - for( integer ic = 0; ic < NC; ++ic ) - { - localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL) + ic+1] = -dAvgMassDens_dCompNext[ic] * gravD; - localPresRelJacobian[TAG::CURRENT *(NC+1) + ic+1] = -dAvgMassDens_dCompCurrent[ic] * gravD; - } - if constexpr ( IS_THERMAL ) - { - localPresRelJacobian[TAG::NEXT *(NC+1+IS_THERMAL)+NC+1] = 0.5 * dTotalMassDensNext[Deriv::dT]; - localPresRelJacobian[TAG::CURRENT *(NC+1)+1] = 0.5 * dTotalMassDens[Deriv::dT]; - } - */ - } - -}; - - - -struct WellElementPhaseFlux -{ - /** - * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head - * @tparam numComp number of components - * @param numPhase number of phases - * @param ip phase index - * @param pres pressure - * @param gravCoef gravitational coefficient - * @param dPhaseVolFrac derivative of phase volume fraction wrt pressure, temperature, comp density - * @param dCompFrac_dCompDens derivative of component fraction wrt component density - * @param phaseMassDens phase mass density - * @param dPhaseMassDens derivative of phase mass density wrt pressure, temperature, comp fraction - * @param potGrad potential gradient for this phase - * @param phaseFlux phase flux - * @param dPhaseFlux derivatives of phase flux - */ - template< integer numComp, integer IS_THERMAL > - GEOS_HOST_DEVICE - static void - compute( integer const ip, - real64 const & gravCoef, - real64 const & gravCoefNext, - real64 const & pres, - real64 const & presNext, - real64 const & totalMassDens, - real64 const & totalMassDensNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDensNext, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDens, - arraySlice1d< real64 const, compflow::USD_FLUID_DC - 1 > const & dTotalMassDens_dCompDensNext, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > const & phaseMassDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > const & dPhaseMassDens, - real64 & potGrad, - real64 ( &phaseFlux ), - real64 ( & dPhaseFlux )[numComp+1+IS_THERMAL] ) - { - real64 dPresGrad_dP[numFluxSupportPoints]{}; - real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; - real64 dGravHead_dP[numFluxSupportPoints]{}; - real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; - PotGrad::compute< numComp, IS_THERMAL >( gravCoef - , gravCoefNext - , pres - , presNext - , totalMassDens - , totalMassDensNext - , dTotalMassDens - , dTotalMassDensNext - , dTotalMassDens_dCompDens - , dTotalMassDens_dCompDensNex ); - - // gravity head - real64 gravHead = gravCoef - gravCoefNext - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - real64 const gravD = trans[i] * gravCoef[er][esr][ei]; - - gravHead += gravD; - } - - // *** upwinding *** - - // phase flux and derivatives - - // assuming TPFA in the code below - - real64 Ttrans = fabs( trans[0] ); - potGrad = potGrad / Ttrans; - - real64 const mobility_i = phaseMob[seri[0]][sesri[0]][sei[0]][ip]; - real64 const mobility_j = phaseMob[seri[1]][sesri[1]][sei[1]][ip]; - - // compute phase flux, see Eqs. (66) and (69) from the reference above - real64 smoEps = epsC1PPU; - if( fabs( gravHead ) <= 1e-20 ) - smoEps = 1000; - real64 const tmpSqrt = sqrt( potGrad * potGrad + smoEps * smoEps ); - real64 const smoMax = 0.5 * (-potGrad + tmpSqrt); - - phaseFlux = potGrad * mobility_i - smoMax * (mobility_j - mobility_i) ); - - // derivativess - - // first part, mobility derivative - - // dP - { - real64 const dMob_dP = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip][Deriv::dP]; - dPhaseFlux_dP[0] += Ttrans * potGrad * dMob_dP; - } - - // dC - { - arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > - dPhaseMobSub = dPhaseMob[seri[0]][sesri[0]][sei[0]][ip]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[0][jc] += Ttrans * potGrad * dPhaseMobSub[Deriv::dC + jc]; - } - } - - real64 const tmpInv = 1.0 / tmpSqrt; - real64 const dSmoMax_x = 0.5 * (1.0 - potGrad * tmpInv); - - // pressure gradient and mobility difference depend on all points in the stencil - real64 const dMobDiff_sign[numFluxSupportPoints] = {-1.0, 1.0}; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - // dP - - real64 const dPotGrad_dP = dPresGrad_dP[ke] - dGravHead_dP[ke]; - - // first part - dPhaseFlux_dP[ke] += dPotGrad_dP * mobility_i; - - // second part - real64 const dSmoMax_dP = -dPotGrad_dP * dSmoMax_x; - dPhaseFlux_dP[ke] += -dSmoMax_dP * (mobility_j - mobility_i); - - real64 const dMob_dP = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip][Deriv::dP]; - dPhaseFlux_dP[ke] += -Ttrans * smoMax * dMobDiff_sign[ke] * dMob_dP; - - // dC - - arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > - dPhaseMobSub = dPhaseMob[seri[ke]][sesri[ke]][sei[ke]][ip]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - real64 const dPotGrad_dC = dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; - - // first part - dPhaseFlux_dC[ke][jc] += dPotGrad_dC * mobility_i; - - // second part - real64 const dSmoMax_dC = -dPotGrad_dC * dSmoMax_x; - dPhaseFlux_dC[ke][jc] += -dSmoMax_dC * (mobility_j - mobility_i); - dPhaseFlux_dC[ke][jc] += -Ttrans * smoMax * dMobDiff_sign[ke] * dPhaseMobSub[Deriv::dC + jc]; - } - } - - - } -}; - - -} // namespace wellElementKernelUtilities - -} // namespace geosx - - -#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLELEMENTKERNELS_HPP From f508369d3adb0c38304703a63af605e7fc83a2be Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 18 Jun 2024 08:19:55 -0700 Subject: [PATCH 35/71] move mpi com outside of subregion loop --- .../wells/CompositionalMultiphaseWell.cpp | 40 ++++++++++++++----- .../wells/CompositionalMultiphaseWell.hpp | 6 ++- .../fluidFlow/wells/SinglePhaseWell.cpp | 3 +- .../fluidFlow/wells/SinglePhaseWell.hpp | 2 +- .../fluidFlow/wells/WellSolverBase.hpp | 2 +- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 95de4386092..dc4711bff5a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -77,8 +77,8 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, setInputFlag( InputFlags::OPTIONAL ). setDescription( "Use mass formulation instead of molar" ); - this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useTotalMassEquation ). - setApplyDefaultValue( 0 ). + this->registerWrapper( viewKeyStruct::useTotalMassEquationString(), &m_useTotalMassEquation ). + setApplyDefaultValue( 1 ). setInputFlag( InputFlags::OPTIONAL ). setDescription( "Use total mass equation" ); @@ -766,7 +766,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg real64 const currentTotalRate = connRate[iwelemRef]; // Step 2.1: compute the inverse of the total density and derivatives - massDensity =totalDens[iwelemRef][0]; // need to verify this is surface dens + massDensity =totalDens[iwelemRef][0]; real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0]; stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp ); @@ -878,7 +878,7 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe } -void CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const +real64 CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const { GEOS_MARK_FUNCTION; @@ -900,8 +900,7 @@ void CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegio subRegion, fluid ); - maxDeltaPhaseVolFrac = MpiWrapper::max( maxDeltaPhaseVolFrac ); - + return maxDeltaPhaseVolFrac; } void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & subRegion ) const @@ -926,7 +925,29 @@ void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & } -void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) +void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) +{ + GEOS_MARK_FUNCTION; + + real64 maxPhaseVolFrac = 0.0; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, + MeshLevel & mesh, + arrayView1d< string const > const & regionNames ) + { + mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) + { + real64 const maxRegionPhaseVolFrac = updateSubRegionState( subRegion ); + maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac ); + } ); + } ); + maxPhaseVolFrac = MpiWrapper::max( maxPhaseVolFrac ); + + GEOS_LOG_LEVEL_RANK_0( 1, GEOS_FMT( " {}: Max well phase volume fraction change = {}", getName(), fmt::format( "{:.{}f}", maxPhaseVolFrac, 4 ) ) ); + +} + +real64 CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update properties updateGlobalComponentFraction( subRegion ); @@ -937,11 +958,12 @@ void CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & s // update densities, phase fractions, phase volume fractions - updateFluidModel( subRegion ); // Calculate fluid properties; - updatePhaseVolumeFraction( subRegion ); + updateFluidModel( subRegion ); // Calculate fluid properties; + real64 maxPhaseVolChange = updatePhaseVolumeFraction( subRegion ); updateTotalMassDensity( subRegion ); // update the current BHP pressure updateBHPForConstraint( subRegion ); + return maxPhaseVolChange; } void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index dfa23de36f8..bf4acb943f8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -164,7 +164,7 @@ class CompositionalMultiphaseWell : public WellSolverBase * @param subRegion the well subregion containing all the primary and dependent fields * @param targetIndex the targetIndex of the subRegion */ - void updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const; + real64 updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const; /** * @brief Recompute total mass densities from mass density and phase volume fractions @@ -183,7 +183,9 @@ class CompositionalMultiphaseWell : public WellSolverBase * @brief Recompute all dependent quantities from primary variables (including constitutive models) * @param subRegion the well subregion containing all the primary and dependent fields */ - virtual void updateSubRegionState( WellElementSubRegion & subRegion ) override; + virtual void updateState( DomainPartition & domain ) override; + + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; virtual string wellElementDofName() const override { return viewKeyStruct::dofFieldString(); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 50859c4fde0..033bcd97738 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -379,7 +379,7 @@ void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const } ); } -void SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) +real64 SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update volumetric rates for the well constraints // Warning! This must be called before updating the fluid model @@ -392,6 +392,7 @@ void SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) updateBHPForConstraint( subRegion ); // note: the perforation rates are updated separately + return 0.0; // change in phasevolume fraction doesnt apply } void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index a9c0177885f..41a93c692b7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -166,7 +166,7 @@ class SinglePhaseWell : public WellSolverBase * @brief Recompute all dependent quantities from primary variables (including constitutive models) on the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual void updateSubRegionState( WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; /** * @brief assembles the flux terms for all connections between well elements diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 3e0d5008739..b92990a5a70 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -276,7 +276,7 @@ class WellSolverBase : public SolverBase * @brief Recompute all dependent quantities from primary variables (including constitutive models) * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual void updateSubRegionState( WellElementSubRegion & subRegion ) = 0; + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) = 0; /** * @brief Recompute the perforation rates for all the wells From bce0bf94cb8635411a788ef4ac4556c1110d20b0 Mon Sep 17 00:00:00 2001 From: tjb Date: Tue, 18 Jun 2024 09:57:52 -0700 Subject: [PATCH 36/71] build fix for ubunnto etal --- .../multiphysics/CoupledReservoirAndWellKernels.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 3a977c76ada..48b1e1eb508 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -22,6 +22,7 @@ #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/SolverBaseKernels.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" From a1b70aceed168fff32f33bbcaee6e4f53295b351 Mon Sep 17 00:00:00 2001 From: tjb Date: Tue, 18 Jun 2024 10:28:16 -0700 Subject: [PATCH 37/71] build fix for ubunnto etal t2 --- .../multiphysics/CoupledReservoirAndWellKernels.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 48b1e1eb508..b783a870743 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -23,8 +23,6 @@ #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" #include "constitutive/fluid/multifluid/Layouts.hpp" -#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" -#include "physicsSolvers/SolverBaseKernels.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellTags.hpp" #include "physicsSolvers/fluidFlow/wells/WellFields.hpp" From b3ed4751baf4f6b9ac80df127f53e0f00fa72808 Mon Sep 17 00:00:00 2001 From: tjb Date: Tue, 18 Jun 2024 11:04:37 -0700 Subject: [PATCH 38/71] build fix for ubunnto etal t3 --- .../multiphysics/CompositionalMultiphaseReservoirAndWells.cpp | 3 ++- .../multiphysics/CoupledReservoirAndWellKernels.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp index 84d881ed980..6ec5b7d3b43 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.cpp @@ -22,6 +22,7 @@ #include "common/TimingMacros.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "mesh/PerforationFields.hpp" +#include "physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" @@ -30,7 +31,7 @@ #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/multiphysics/MultiphasePoromechanics.hpp" -#include "physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp" + namespace geos { diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index b783a870743..174758ad7ee 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -23,6 +23,7 @@ #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" #include "constitutive/fluid/multifluid/Layouts.hpp" +#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellTags.hpp" #include "physicsSolvers/fluidFlow/wells/WellFields.hpp" From e4edc2181bc2e9944f2d79987f8280245ef9919a Mon Sep 17 00:00:00 2001 From: tjb Date: Tue, 18 Jun 2024 14:14:15 -0700 Subject: [PATCH 39/71] move input file data to char array, write out array to file, delete file --- .../unitTests/wellsTests/co2flash.txt | 1 - .../unitTests/wellsTests/pvtgas.txt | 3 -- .../unitTests/wellsTests/pvtliquid.txt | 3 -- ...eservoirCompositionalMultiphaseMSWells.cpp | 26 +++++++++++++++ ...eservoirCompositionalMultiphaseSSWells.cpp | 32 +++++++++++++++++-- ...eservoirCompositionalMultiphaseMSWells.cpp | 28 ++++++++++++++++ ...eservoirCompositionalMultiphaseSSWells.cpp | 29 +++++++++++++++++ 7 files changed, 112 insertions(+), 10 deletions(-) delete mode 100644 src/coreComponents/unitTests/wellsTests/co2flash.txt delete mode 100644 src/coreComponents/unitTests/wellsTests/pvtgas.txt delete mode 100644 src/coreComponents/unitTests/wellsTests/pvtliquid.txt diff --git a/src/coreComponents/unitTests/wellsTests/co2flash.txt b/src/coreComponents/unitTests/wellsTests/co2flash.txt deleted file mode 100644 index 4c5a766d852..00000000000 --- a/src/coreComponents/unitTests/wellsTests/co2flash.txt +++ /dev/null @@ -1 +0,0 @@ -FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0 diff --git a/src/coreComponents/unitTests/wellsTests/pvtgas.txt b/src/coreComponents/unitTests/wellsTests/pvtgas.txt deleted file mode 100644 index ccd4e817f67..00000000000 --- a/src/coreComponents/unitTests/wellsTests/pvtgas.txt +++ /dev/null @@ -1,3 +0,0 @@ -DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10 -ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10 -EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10 diff --git a/src/coreComponents/unitTests/wellsTests/pvtliquid.txt b/src/coreComponents/unitTests/wellsTests/pvtliquid.txt deleted file mode 100644 index 4df0c25f042..00000000000 --- a/src/coreComponents/unitTests/wellsTests/pvtliquid.txt +++ /dev/null @@ -1,3 +0,0 @@ -DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0 -ViscosityFun PhillipsBrineViscosity 0 -EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0 diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp index 3909a24cd76..b11f2518a0a 100644 --- a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp @@ -35,7 +35,27 @@ using namespace geos::constitutive; using namespace geos::testing; CommandLineOptions g_commandLineOptions; +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 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; char const * xmlInput = R"xml( @@ -643,9 +663,15 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Press int main( int argc, char * * argv ) { + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); ::testing::InitGoogleTest( &argc, argv ); g_commandLineOptions = *geos::basicSetup( argc, argv ); int const result = RUN_ALL_TESTS(); geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile("pvtliquid.txt"); + removeFile("pvtgas.txt"); return result; } diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp index 25e01551e6c..4ef7d20cb8c 100644 --- a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp @@ -35,7 +35,27 @@ using namespace geos::constitutive; using namespace geos::testing; CommandLineOptions g_commandLineOptions; +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 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; char const * xmlInput = R"xml( @@ -645,7 +665,7 @@ real64 constexpr CompositionalMultiphaseReservoirSolverTest::time; real64 constexpr CompositionalMultiphaseReservoirSolverTest::dt; real64 constexpr CompositionalMultiphaseReservoirSolverTest::eps; -#if 1 +#if 0 TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perforation ) { @@ -666,7 +686,7 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perfo #endif -#if 0 +#if 1 TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum ) { real64 const perturb = std::sqrt( eps ); @@ -678,7 +698,7 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleAccumulationTerms( domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleAccumulationTerms(time,dt, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } #endif @@ -735,9 +755,15 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Press #endif int main( int argc, char * * argv ) { + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); ::testing::InitGoogleTest( &argc, argv ); g_commandLineOptions = *geos::basicSetup( argc, argv ); int const result = RUN_ALL_TESTS(); geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile("pvtliquid.txt"); + removeFile("pvtgas.txt"); return result; } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 2a6833f3445..e5697853a4a 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -36,6 +36,27 @@ using namespace geos::testing; CommandLineOptions g_commandLineOptions; +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 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; char const * xmlInput = R"xml( @@ -786,9 +807,16 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Press #endif int main( int argc, char * * argv ) { + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); ::testing::InitGoogleTest( &argc, argv ); g_commandLineOptions = *geos::basicSetup( argc, argv ); int const result = RUN_ALL_TESTS(); geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile("pvtliquid.txt"); + removeFile("pvtgas.txt"); + return result; } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp index bd6ee39cacf..dda5f4f2b02 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -36,6 +36,28 @@ using namespace geos::testing; CommandLineOptions g_commandLineOptions; +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 ); +} +char const * co2flash = "FlashModel CO2Solubility 1e6 7.5e7 5e5 299.15 369.15 10 0"; +char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 369.15 10 0\n" + "ViscosityFun PhillipsBrineViscosity 0\n" + "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; + +char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; + char const * xmlInput = R"xml( @@ -774,9 +796,16 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Press #endif int main( int argc, char * * argv ) { + writeTableToFile( "co2flash.txt", co2flash ); + writeTableToFile( "pvtliquid.txt", pvtLiquid ); + writeTableToFile( "pvtgas.txt", pvtGas ); ::testing::InitGoogleTest( &argc, argv ); g_commandLineOptions = *geos::basicSetup( argc, argv ); int const result = RUN_ALL_TESTS(); geos::basicCleanup(); + removeFile( "co2flash.txt" ); + removeFile("pvtliquid.txt"); + removeFile("pvtgas.txt"); + return result; } From 352ca5d405b714a6ba3e311a3af62c51c273ba92 Mon Sep 17 00:00:00 2001 From: tjb Date: Tue, 18 Jun 2024 14:37:08 -0700 Subject: [PATCH 40/71] uncrustify --- ...hermalReservoirCompositionalMultiphaseMSWells.cpp | 8 ++++---- ...hermalReservoirCompositionalMultiphaseSSWells.cpp | 10 +++++----- ...hermalReservoirCompositionalMultiphaseMSWells.cpp | 10 +++++----- ...hermalReservoirCompositionalMultiphaseSSWells.cpp | 12 ++++++------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp index b11f2518a0a..84362ec0698 100644 --- a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp @@ -54,8 +54,8 @@ char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 3 "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" - "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" - "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; char const * xmlInput = R"xml( @@ -671,7 +671,7 @@ int main( int argc, char * * argv ) int const result = RUN_ALL_TESTS(); geos::basicCleanup(); removeFile( "co2flash.txt" ); - removeFile("pvtliquid.txt"); - removeFile("pvtgas.txt"); + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); return result; } diff --git a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp index 4ef7d20cb8c..b7b63b1033e 100644 --- a/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp @@ -54,8 +54,8 @@ char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 3 "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" - "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" - "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; char const * xmlInput = R"xml( @@ -698,7 +698,7 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Accum [&] ( CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { - solver->wellSolver()->assembleAccumulationTerms(time,dt, domain, solver->getDofManager(), localMatrix, localRhs ); + solver->wellSolver()->assembleAccumulationTerms( time, dt, domain, solver->getDofManager(), localMatrix, localRhs ); } ); } #endif @@ -763,7 +763,7 @@ int main( int argc, char * * argv ) int const result = RUN_ALL_TESTS(); geos::basicCleanup(); removeFile( "co2flash.txt" ); - removeFile("pvtliquid.txt"); - removeFile("pvtgas.txt"); + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); return result; } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index e5697853a4a..a29148f8015 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -55,8 +55,8 @@ char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 3 "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" - "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" - "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; char const * xmlInput = R"xml( @@ -815,8 +815,8 @@ int main( int argc, char * * argv ) int const result = RUN_ALL_TESTS(); geos::basicCleanup(); removeFile( "co2flash.txt" ); - removeFile("pvtliquid.txt"); - removeFile("pvtgas.txt"); - + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); + return result; } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp index dda5f4f2b02..4b6712c172f 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -55,9 +55,9 @@ char const * pvtLiquid = "DensityFun PhillipsBrineDensity 1e6 7.5e7 5e5 299.15 3 "EnthalpyFun BrineEnthalpy 1e6 7.5e7 5e5 299.15 369.15 10 0\n"; char const * pvtGas = "DensityFun SpanWagnerCO2Density 1e6 7.5e7 5e5 299.15 369.15 10\n" - "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" - "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; - + "ViscosityFun FenghourCO2Viscosity 1e6 7.5e7 5e5 299.15 369.15 10\n" + "EnthalpyFun CO2Enthalpy 1e6 7.5e7 5e5 299.15 369.15 10\n"; + char const * xmlInput = R"xml( @@ -804,8 +804,8 @@ int main( int argc, char * * argv ) int const result = RUN_ALL_TESTS(); geos::basicCleanup(); removeFile( "co2flash.txt" ); - removeFile("pvtliquid.txt"); - removeFile("pvtgas.txt"); - + removeFile( "pvtliquid.txt" ); + removeFile( "pvtgas.txt" ); + return result; } From 574a18ef80021c2a4294d0b29615477884b22ca0 Mon Sep 17 00:00:00 2001 From: tjb Date: Tue, 18 Jun 2024 14:46:29 -0700 Subject: [PATCH 41/71] testing --- .../fluidFlow/wells/CompositionalMultiphaseWell.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index dc4711bff5a..cb4e751febb 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -71,7 +71,6 @@ CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, m_allowCompDensChopping( 1 ), m_targetPhaseIndex( -1 ) { - this->registerWrapper( viewKeyStruct::useMassFlagString(), &m_useMass ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). From 25fae7f525395829434d6f73f0be9ee2ade9783c Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 19 Jun 2024 08:08:49 -0700 Subject: [PATCH 42/71] remove dead code --- .../CompositionalMultiphaseWellKernels.cpp | 112 ------------------ 1 file changed, 112 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index e3236ba5b0d..9d9c191f2a5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -473,118 +473,6 @@ INST_PressureRelationKernel( 4, 1 ); INST_PressureRelationKernel( 5, 0 ); INST_PressureRelationKernel( 5, 1 ); - -/******************************** VolumeBalanceKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -VolumeBalanceKernel:: - compute( integer const numPhases, - real64 const & volume, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const & phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const & dPhaseVolFrac, - real64 & localVolBalance, - real64 ( & localVolBalanceJacobian )[NC+1] ) -{ - using Deriv = multifluid::DerivativeOffset; - - localVolBalance = 1.0; - for( integer ic = 0; ic < NC+1; ++ic ) - { - localVolBalanceJacobian[ic] = 0.0; - } - - // sum contributions to component accumulation from each phase - for( integer ip = 0; ip < numPhases; ++ip ) - { - localVolBalance -= phaseVolFrac[ip]; - localVolBalanceJacobian[0] -= dPhaseVolFrac[ip][Deriv::dP]; - - for( integer jc = 0; jc < NC; ++jc ) - { - localVolBalanceJacobian[jc + 1] -= dPhaseVolFrac[ip][Deriv::dC+jc]; - } - } - - // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) - for( integer idof = 0; idof < NC+1; ++idof ) - { - localVolBalanceJacobian[idof] *= volume; - } - localVolBalance *= volume; -} - -template< integer NC > -void -VolumeBalanceKernel:: - launch( localIndex const size, - integer const numPhases, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & wellElemDofNumber, - arrayView1d< integer const > const & wellElemGhostRank, - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, - arrayView1d< real64 const > const & wellElemVolume, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - - if( wellElemGhostRank[iwelem] >= 0 ) - { - return; - } - - real64 localVolBalance = 1.0; - real64 localVolBalanceJacobian[NC+1]{}; - - compute< NC >( numPhases, - wellElemVolume[iwelem], - wellElemPhaseVolFrac[iwelem], - dWellElemPhaseVolFrac[iwelem], - localVolBalance, - localVolBalanceJacobian ); - - // get equation/dof indices - localIndex const localVolBalanceEqnIndex = wellElemDofNumber[iwelem] - rankOffset + ROFFSET::MASSBAL + NC; - globalIndex localVolBalanceDOF[NC+1]{}; - for( integer jdof = 0; jdof < NC+1; ++jdof ) - { - localVolBalanceDOF[jdof] = wellElemDofNumber[iwelem] + COFFSET::DPRES + jdof; - } - - localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( localVolBalanceEqnIndex, - localVolBalanceDOF, - localVolBalanceJacobian, - NC+1 ); - localRhs[localVolBalanceEqnIndex] += localVolBalance; - } ); -} - -#define INST_VolumeBalanceKernel( NC ) \ - template \ - void VolumeBalanceKernel:: \ - launch< NC >( localIndex const size, \ - integer const numPhases, \ - globalIndex const rankOffset, \ - arrayView1d< globalIndex const > const & wellElemDofNumber, \ - arrayView1d< integer const > const & wellElemGhostRank, \ - arrayView2d< real64 const, compflow::USD_PHASE > const & wellElemPhaseVolFrac, \ - arrayView3d< real64 const, compflow::USD_PHASE_DC > const & dWellElemPhaseVolFrac, \ - arrayView1d< real64 const > const & wellElemVolume, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_VolumeBalanceKernel( 1 ); -INST_VolumeBalanceKernel( 2 ); -INST_VolumeBalanceKernel( 3 ); -INST_VolumeBalanceKernel( 4 ); -INST_VolumeBalanceKernel( 5 ); - -/******************************** PresTempCompFracInitializationKernel ********************************/ - void PresTempCompFracInitializationKernel:: launch( localIndex const perforationSize, From 371eb04940035e2b41cbeb3d43773d12b14a3d2d Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Fri, 21 Jun 2024 14:47:33 -0700 Subject: [PATCH 43/71] mpi parallel fix for closed wells --- .../fluidFlow/wells/CompositionalMultiphaseWell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index cb4e751febb..b4f8dcd352b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1228,7 +1228,7 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time &cindex, &unity, 1 ); - localRhs[cindex] = 0.0; + localRhs[rindex] = 0.0; } } } ); From 9c7a462cfe23fca83a1a737d124c6a4e5e87d80e Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 9 Jul 2024 13:11:29 -0700 Subject: [PATCH 44/71] 1) fix temp constraint eqn setup for well spanning > 1 cores , 2) well debug moved to well_debug branch, 3) stored global indices for well segs, 4) stored global reservoir indices for perfs, 5) added interfaces to access newton iteration number --- src/coreComponents/mesh/PerforationData.cpp | 2 + src/coreComponents/mesh/PerforationData.hpp | 17 ++++ src/coreComponents/mesh/PerforationFields.hpp | 8 ++ .../mesh/WellElementSubRegion.cpp | 31 +++++-- .../mesh/WellElementSubRegion.hpp | 11 +++ .../physicsSolvers/SolverStatistics.cpp | 11 +++ .../physicsSolvers/SolverStatistics.hpp | 10 +- .../CompositionalMultiphaseWellKernels.hpp | 26 ++++-- ...rmalCompositionalMultiphaseWellKernels.hpp | 93 +++++++++++-------- .../CoupledReservoirAndWellKernels.hpp | 11 ++- ...eservoirCompositionalMultiphaseMSWells.cpp | 2 +- 11 files changed, 159 insertions(+), 63 deletions(-) diff --git a/src/coreComponents/mesh/PerforationData.cpp b/src/coreComponents/mesh/PerforationData.cpp index e7453add682..facd35c76b5 100644 --- a/src/coreComponents/mesh/PerforationData.cpp +++ b/src/coreComponents/mesh/PerforationData.cpp @@ -38,6 +38,8 @@ PerforationData::PerforationData( string const & name, Group * const parent ) registerField( fields::perforation::reservoirElementRegion{}, &m_toMeshElements.m_toElementRegion ); registerField( fields::perforation::reservoirElementSubRegion{}, &m_toMeshElements.m_toElementSubRegion ); registerField( fields::perforation::reservoirElementIndex{}, &m_toMeshElements.m_toElementIndex ); + registerField( fields::perforation::reservoirElementGlobalIndex{}, &m_reservoirElementGlobalIndex ); + registerField( fields::perforation::wellElementIndex{}, &m_wellElementIndex ); registerField( fields::perforation::location{}, &m_location ); registerField( fields::perforation::wellTransmissibility{}, &m_wellTransmissibility ); diff --git a/src/coreComponents/mesh/PerforationData.hpp b/src/coreComponents/mesh/PerforationData.hpp index 0c3a4828e03..caf1f9a808b 100644 --- a/src/coreComponents/mesh/PerforationData.hpp +++ b/src/coreComponents/mesh/PerforationData.hpp @@ -149,6 +149,20 @@ class PerforationData : public ObjectManagerBase */ arrayView1d< localIndex const > getWellElements() const { return m_wellElementIndex; } + /** + * @brief Get perforation-to-reservoir-element connectivity. + * @return list of global reservoir element index connected to each perforation + */ + arrayView1d< globalIndex > getReservoirElementGlobalIndex() { return m_reservoirElementGlobalIndex; } + + + + /** + * @brief Provide an immutable accessor to a const perforation-to-reservoir-element connectivity. + * @return list of well element index connected to each perforation + */ + arrayView1d< globalIndex const > getReservoirElementGlobalIndex() const { return m_reservoirElementGlobalIndex; } + /** * @brief Get perforation locations. @@ -274,6 +288,9 @@ class PerforationData : public ObjectManagerBase /// Indices of the well elements to which perforations are attached array1d< localIndex > m_wellElementIndex; + /// Global indices of reservoir cell containing perforation + array1d< globalIndex > m_reservoirElementGlobalIndex; + /// Location of the perforations array2d< real64 > m_location; diff --git a/src/coreComponents/mesh/PerforationFields.hpp b/src/coreComponents/mesh/PerforationFields.hpp index 43451e8ec04..bf538f56bac 100644 --- a/src/coreComponents/mesh/PerforationFields.hpp +++ b/src/coreComponents/mesh/PerforationFields.hpp @@ -57,6 +57,14 @@ DECLARE_FIELD( reservoirElementIndex, WRITE_AND_READ, "For each perforation, element index of the perforated element" ); +DECLARE_FIELD( reservoirElementGlobalIndex, + "reservoirElementGlobalIndex", + array1d< globalIndex >, + 0, + NOPLOT, + WRITE_AND_READ, + "For each perforation, global element index of the perforated element" ); + DECLARE_FIELD( wellElementIndex, "wellElementIndex", array1d< localIndex >, diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index f6046b802c4..4bc9edfc289 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -154,7 +154,8 @@ bool visitNeighborElements( MeshLevel const & mesh, SortedArray< globalIndex > & elements, localIndex & erMatched, localIndex & esrMatched, - localIndex & eiMatched ) + localIndex & eiMatched, + globalIndex & giMatched ) { ElementRegionManager const & elemManager = mesh.getElemManager(); NodeManager const & nodeManager = mesh.getNodeManager(); @@ -163,7 +164,7 @@ bool visitNeighborElements( MeshLevel const & mesh, ArrayOfArraysView< localIndex const > const & toElementRegionList = nodeManager.elementRegionList(); ArrayOfArraysView< localIndex const > const & toElementSubRegionList = nodeManager.elementSubRegionList(); ArrayOfArraysView< localIndex const > const & toElementList = nodeManager.elementList(); - + arrayView1d< globalIndex const > localToGlobalIndex = nodeManager.localToGlobalMap(); arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const referencePosition = nodeManager.referencePosition().toViewConst(); @@ -182,7 +183,7 @@ bool visitNeighborElements( MeshLevel const & mesh, // that contains only the nodes that have already been visited // the newly added nodes will be added to "nodes" SortedArray< localIndex > currNodes = nodes; - + giMatched = -1; // for all the nodes already visited for( localIndex currNode : currNodes ) { @@ -192,7 +193,7 @@ bool visitNeighborElements( MeshLevel const & mesh, localIndex const er = toElementRegionList[currNode][b]; localIndex const esr = toElementSubRegionList[currNode][b]; localIndex const eiLocal = toElementList[currNode][b]; - + globalIndex const gIndex = localToGlobalIndex[eiLocal]; CellElementRegion const & region = elemManager.getRegion< CellElementRegion >( er ); CellElementSubRegion const & subRegion = region.getSubRegion< CellElementSubRegion >( esr ); arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList(); @@ -220,6 +221,7 @@ bool visitNeighborElements( MeshLevel const & mesh, erMatched = er; esrMatched = esr; eiMatched = eiLocal; + giMatched = gIndex; matched = true; break; } @@ -300,7 +302,8 @@ bool searchLocalElements( MeshLevel const & mesh, localIndex const & eiInit, localIndex & erMatched, localIndex & esrMatched, - localIndex & eiMatched ) + localIndex & eiMatched, + globalIndex & giMatched ) { // search locally, starting from the location of the previous perforation // the assumption here is that perforations have been entered in order of depth @@ -323,7 +326,6 @@ bool searchLocalElements( MeshLevel const & mesh, // collect the nodes of the current element // they will be used to access the neighbors and check if they contain the perforation collectElementNodes( subRegion, eiInit, nodes ); - // if no match is found, enlarge the neighborhood m_searchDepth'th times for( localIndex d = 0; d < searchDepth; ++d ) { @@ -333,7 +335,7 @@ bool searchLocalElements( MeshLevel const & mesh, // stop if a reservoir element containing the perforation is found // if not, enlarge the set "nodes" resElemFound = visitNeighborElements( mesh, location, nodes, elements, - erMatched, esrMatched, eiMatched ); + erMatched, esrMatched, eiMatched, giMatched ); if( resElemFound || nNodes == nodes.size()) { break; @@ -432,6 +434,14 @@ void WellElementSubRegion::generate( MeshLevel & mesh, // this assumes that the elemToNodes maps has been filled at Step 5) updateNodeManagerNodeToElementMap( mesh ); + // Store local to global index mapping + integer n_localElems = localElems.size(); + m_globalWellElementIndex.resize( n_localElems ); + for( integer i=0; i getGlobalWellElementIndex() const + { + return m_globalWellElementIndex; + } /** * @brief Set the name of the WellControls object of this well. * @param[in] name the name of the WellControls object @@ -393,6 +401,9 @@ class WellElementSubRegion : public ElementSubRegionBase /// Element-to-node relation is one to one relation. NodeMapType m_toNodesRelation; + /// Local indices of the next well element (used in solvers) + array1d< globalIndex > m_globalWellElementIndex; + /// Local indices of the next well element (used in solvers) array1d< localIndex > m_nextWellElementIndex; diff --git a/src/coreComponents/physicsSolvers/SolverStatistics.cpp b/src/coreComponents/physicsSolvers/SolverStatistics.cpp index f3687b46042..b54fe662f73 100644 --- a/src/coreComponents/physicsSolvers/SolverStatistics.cpp +++ b/src/coreComponents/physicsSolvers/SolverStatistics.cpp @@ -37,6 +37,17 @@ SolverStatistics::SolverStatistics( string const & name, Group * const parent ) setApplyDefaultValue( 0 ). setDescription( "Number of time step cuts" ); + registerWrapper( viewKeyStruct::numCurrentOuterLoopIterationsString(), &m_currentNumOuterLoopIterations ). + setApplyDefaultValue( 0 ). + setDescription( "Cumulative number of current outer loop iterations" ); + + registerWrapper( viewKeyStruct::numCurrentNonlinearIterationsString(), &m_currentNumNonlinearIterations ). + setApplyDefaultValue( 0 ). + setDescription( "Cumulative number of current nonlinear iterations" ); + + registerWrapper( viewKeyStruct::numCurrentLinearIterationsString(), &m_currentNumLinearIterations ). + setApplyDefaultValue( 0 ). + setDescription( "Cumulative number of current linear iterations" ); registerWrapper( viewKeyStruct::numSuccessfulOuterLoopIterationsString(), &m_numSuccessfulOuterLoopIterations ). setApplyDefaultValue( 0 ). diff --git a/src/coreComponents/physicsSolvers/SolverStatistics.hpp b/src/coreComponents/physicsSolvers/SolverStatistics.hpp index 964cbc078ca..b0e0fe24d1d 100644 --- a/src/coreComponents/physicsSolvers/SolverStatistics.hpp +++ b/src/coreComponents/physicsSolvers/SolverStatistics.hpp @@ -127,7 +127,6 @@ class SolverStatistics : public dataRepository::Group integer getNumDiscardedLinearIterations() const { return m_numDiscardedLinearIterations; } -private: /** * @brief Struct to serve as a container for variable strings and keys. @@ -140,6 +139,14 @@ class SolverStatistics : public dataRepository::Group /// String key for the number of time step cuts static constexpr char const * numTimeStepCutsString() { return "numTimeStepCuts"; } + + /// String key for the current number of outer loop iterations + static constexpr char const * numCurrentOuterLoopIterationsString() { return "numCurrentOuterLoopIterations"; } + /// String key for the current number of nonlinear iterations + static constexpr char const * numCurrentNonlinearIterationsString() { return "numCurrentNonlinearIterations"; } + /// String key for the current number of linear iterations + static constexpr char const * numCurrentLinearIterationsString() { return "numCurrentLinearIterations"; } + /// String key for the successful number of outer loop iterations static constexpr char const * numSuccessfulOuterLoopIterationsString() { return "numSuccessfulOuterLoopIterations"; } /// String key for the successful number of nonlinear iterations @@ -155,6 +162,7 @@ class SolverStatistics : public dataRepository::Group static constexpr char const * numDiscardedLinearIterationsString() { return "numDiscardedLinearIterations"; } }; +private: /// Number of time steps integer m_numTimeSteps; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 5a4542656a7..3de2680db63 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -875,7 +875,7 @@ class ElementBasedAssemblyKernel integer const isProducer, globalIndex const rankOffset, string const dofKey, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, @@ -883,6 +883,7 @@ class ElementBasedAssemblyKernel : m_numPhases( numPhases ), m_isProducer( isProducer ), m_rankOffset( rankOffset ), + m_iwelemControl( subRegion.getTopWellElementIndex() ), m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), m_elemGhostRank( subRegion.ghostRank() ), m_volume( subRegion.getElementVolume() ), @@ -1172,11 +1173,11 @@ class ElementBasedAssemblyKernel if constexpr ( IS_THERMAL) { - if( ei == 0 && !m_isProducer ) + if( ei == m_iwelemControl && !m_isProducer ) { // For top segment energy balance eqn replaced with T(n+1) - T = 0 // No other energy balance derivatives - // Assumption is iwelem =0 is top segment with fixed temp BC + // Assumption is global index == 0 is top segment with fixed temp BC for( integer i=0; i < numComp+1+IS_THERMAL; i++ ) { @@ -1256,6 +1257,9 @@ class ElementBasedAssemblyKernel /// Offset for my MPI rank globalIndex const m_rankOffset; + /// Index of the element where the control is enforced + localIndex const m_iwelemControl; + /// View on the dof numbers arrayView1d< globalIndex const > const m_dofNumber; @@ -1327,7 +1331,7 @@ class ElementBasedAssemblyKernelFactory globalIndex const rankOffset, integer const useTotalMassEquation, string const dofKey, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -1400,7 +1404,7 @@ class FaceBasedAssemblyKernel globalIndex const rankOffset, string const wellDofKey, WellControls const & wellControls, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) @@ -1442,6 +1446,9 @@ class FaceBasedAssemblyKernel // edge indexes + localIndex iwelemUp; + localIndex iwelemNext; + localIndex iwelemCurrent; globalIndex offsetUp; globalIndex offsetCurrent; globalIndex offsetNext; @@ -1714,10 +1721,8 @@ class FaceBasedAssemblyKernel compFracUp[ic] = m_injection[ic]; for( integer jc = 0; jc < NC; ++jc ) { - //dComp[ic][jc] = 0.0; dComp[ic][jc] = m_dWellElemCompFrac_dCompDens[iwelemUp][ic][jc]; } - //for ( integer jc = 0 ;jc < WJ_COFFSET::nDer ; ++jc) for( integer jc = 0; jc < NC; ++jc ) { dCompFlux[ic][WJ_COFFSET::dC+jc] = 0.0; @@ -1768,7 +1773,10 @@ class FaceBasedAssemblyKernel } stack.offsetUp = m_wellElemDofNumber[iwelemUp]; + stack.iwelemUp = iwelemUp; stack.offsetCurrent = m_wellElemDofNumber[iwelem]; + stack.iwelemCurrent= iwelem; + if( iwelemNext < 0 ) // exit connection { @@ -1788,7 +1796,7 @@ class FaceBasedAssemblyKernel ); stack.offsetNext = m_wellElemDofNumber[iwelemNext]; } - + stack.iwelemNext = iwelemNext; compFluxKernelOp( iwelemNext, iwelemUp, currentConnRate, dComp ); } @@ -1881,7 +1889,7 @@ class FaceBasedAssemblyKernelFactory integer const useTotalMassEquation, string const dofKey, WellControls const & wellControls, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp index 02fa75f9c69..280dc6c0959 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/ThermalCompositionalMultiphaseWellKernels.hpp @@ -477,7 +477,7 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El integer const isProducer, globalIndex const rankOffset, string const dofKey, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, @@ -638,7 +638,7 @@ class ElementBasedAssemblyKernelFactory globalIndex const rankOffset, integer const useTotalMassEquation, string const dofKey, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) @@ -717,7 +717,7 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB globalIndex const rankOffset, string const wellDofKey, WellControls const & wellControls, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, @@ -731,6 +731,7 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB , localRhs , kernelFlags ), m_numPhases ( fluid.numFluidPhases()), + m_globalWellElementIndex( subRegion.getGlobalWellElementIndex() ), m_phaseFraction( fluid.phaseFraction()), m_dPhaseFraction( fluid.dPhaseFraction()), m_phaseEnthalpy( fluid.phaseEnthalpy()), @@ -775,42 +776,43 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB inline void complete( localIndex const iwelem, StackVariables & stack ) const { - Base::complete ( iwelem, stack ); using namespace compositionalMultiphaseUtilities; if( stack.numConnectedElems ==1 ) { - if( !m_isProducer ) + // Setup Jacobian global row indicies for energy equation + globalIndex oneSidedEqnRowIndices = stack.offsetUp + WJ_ROFFSET::ENERGYBAL - m_rankOffset; + + if( oneSidedEqnRowIndices >= 0 && oneSidedEqnRowIndices < m_localMatrix.numRows() ) { - // For top segment energy balance eqn replaced with T(n+1) - T = 0 - // No other energy balance derivatives - // Assumption is iwelem =0 is top segment with fixed temp BC - for( integer i=0; i< CP_Deriv::nDer; i++ ) + + if( !m_isProducer && m_globalWellElementIndex[iwelem] == 0 ) { - stack.localEnergyFluxJacobian[0][i] = 0.0; + // For top segment energy balance eqn replaced with T(n+1) - T = 0 + // No other energy balance derivatives + // Assumption is global index == 0 is top segment with fixed temp BC + for( integer i=0; i< CP_Deriv::nDer; i++ ) + { + stack.localEnergyFluxJacobian[0][i] = 0.0; + } + stack.localEnergyFluxJacobian_dQ[0][0]=0; + stack.localEnergyFlux[0]=0; } - stack.localEnergyFluxJacobian_dQ[0][0]=0; - stack.localEnergyFlux[0]=0; - } - // Setup Jacobian global row indicies for energy equation - globalIndex oneSidedEqnRowIndices = stack.offsetUp + WJ_ROFFSET::ENERGYBAL - m_rankOffset; - // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) - globalIndex oneSidedDofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; - globalIndex oneSidedDofColIndices_dPresCompTempUp[CP_Deriv::nDer]{}; - int ioff=0; - oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; - oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; - for( integer jdof = 0; jdof < NC; ++jdof ) - { - oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; - } + // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order) + globalIndex oneSidedDofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ; + globalIndex oneSidedDofColIndices_dPresCompTempUp[CP_Deriv::nDer]{}; + int ioff=0; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP; + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT; + for( integer jdof = 0; jdof < NC; ++jdof ) + { + oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof; + } - if( oneSidedEqnRowIndices >= 0 && oneSidedEqnRowIndices < m_localMatrix.numRows() ) - { m_localMatrix.template addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices, &oneSidedDofColIndices_dRate, stack.localEnergyFluxJacobian_dQ[0], @@ -821,28 +823,34 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB CP_Deriv::nDer ); RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices], stack.localEnergyFlux[0] ); } - } - else // if ( stack.numConnectedElems == 2 ) + else // if ( stack.numConnectedElems == 2 ) { - if( iwelem == 1 && !m_isProducer ) + globalIndex row_current = stack.offsetCurrent + WJ_ROFFSET::ENERGYBAL - m_rankOffset; + globalIndex row_next = stack.offsetNext + WJ_ROFFSET::ENERGYBAL - m_rankOffset; + + if( !m_isProducer ) { - // For top segment energy balance eqn replaced with T(n+1) - T = 0 - // No upstream energy balance derivatives added to segment with control - // Assumption is iwelem =0 is top segment with fixed temp BC - for( integer i=0; i= 0 && row_next < m_localMatrix.numRows() ) + { + if( m_globalWellElementIndex[stack.iwelemNext] == 0 ) + { + for( integer i=0; i m_globalWellElementIndex; + /// Element phase fraction arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseFraction; arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFraction; @@ -1079,7 +1090,7 @@ class FaceBasedAssemblyKernelFactory integer const useTotalMassEquation, string const dofKey, WellControls const & wellControls, - ElementSubRegionBase const & subRegion, + WellElementSubRegion const & subRegion, MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 174758ad7ee..cd7ef201fdd 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -411,6 +411,7 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM numCrossFlowPerforations, kernelFlags ), m_isProducer( isProducer ), + m_globalWellElementIndex( subRegion.getGlobalWellElementIndex() ), m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()) @@ -435,9 +436,12 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM localIndex const iwelem ) { // No energy equation if top element and Injector - if( iwelem ==0 && !m_isProducer ) + // Top element defined by global index == 0 + // Assumption is global index == 0 is top segment with fixed temp BC + if( !m_isProducer ) { - return; + if( m_globalWellElementIndex[iwelem] == 0 ) + return; } // local working variables and arrays stackArray1d< localIndex, 2* numComp > eqnRowIndices( 2 ); @@ -515,6 +519,9 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM /// Well type integer const m_isProducer; + /// Global index of local element + arrayView1d< globalIndex const > m_globalWellElementIndex; + /// Views on energy flux arrayView1d< real64 const > const m_energyPerfFlux; arrayView3d< real64 const > const m_dEnergyPerfFlux; diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index a29148f8015..07d10d568b9 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -736,7 +736,7 @@ TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Perfo #endif -#if 1 +#if 0 TEST_F( CompositionalMultiphaseReservoirSolverTest, jacobianNumericalCheck_Flux ) { real64 const perturb = std::sqrt( eps ); From 2e1bb1e7e9590d3b99eb1ac2b70811001286f8be Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Thu, 11 Jul 2024 13:52:30 -0700 Subject: [PATCH 45/71] resolve latest merge --- .../fluidFlow/wells/CompositionalMultiphaseWell.cpp | 1 + .../physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp | 2 +- .../multiphysics/CompositionalMultiphaseReservoirAndWells.hpp | 2 +- .../testThermalReservoirCompositionalMultiphaseMSWells.cpp | 2 +- .../testThermalReservoirCompositionalMultiphaseSSWells.cpp | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 32676d77ca8..eb19ec8f55d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1422,6 +1422,7 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, + m_maxRelativeCompDensChange, pressure, compDens, pressureScalingFactor, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index ce1801c6d54..28e35e1a2c7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -82,7 +82,7 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< fields::well::temperature_n >( getName() ); subRegion.registerField< fields::well::temperature >( getName() ); - + subRegion.registerField< fields::well::connectionRate_n >( getName() ); subRegion.registerField< fields::well::connectionRate >( getName() ); diff --git a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp index 4effbe54621..f08798e4feb 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CompositionalMultiphaseReservoirAndWells.hpp @@ -83,7 +83,7 @@ class CompositionalMultiphaseReservoirAndWells : public CoupledReservoirAndWells DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; - + integer isThermal() { return flowSolver()->isThermal(); } integer useSimpleAccumulation() const { return flowSolver()->useSimpleAccumulation(); } integer useTotalMassEquation() const { return flowSolver()->useTotalMassEquation(); } integer numFluidPhases() { return flowSolver()->numFluidPhases(); } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 07d10d568b9..6ee690fda82 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -210,7 +210,7 @@ char const * xmlInput = compressibility="1.0e-9"/> Date: Mon, 22 Jul 2024 14:22:08 -0700 Subject: [PATCH 46/71] 1) remove schema addition for current nonlinear stats , 2) remove test code that zeroed energy derivatives if phase not present --- .../constitutive/fluid/multifluid/MultiFluidBase.hpp | 4 ---- .../physicsSolvers/SolverStatistics.cpp | 12 ------------ .../physicsSolvers/SolverStatistics.hpp | 8 -------- 3 files changed, 24 deletions(-) diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp index 22220e0364b..2e570e58dab 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidBase.hpp @@ -1055,10 +1055,6 @@ MultiFluidBase::KernelWrapper:: bool const phaseExists = (phaseFrac.value[ip] > 0); if( !phaseExists ) { - for( integer idof = 0; idof < numDOF; ++idof ) - { - phaseInternalEnergy.derivs[ip][idof] = 0.0; - } continue; } diff --git a/src/coreComponents/physicsSolvers/SolverStatistics.cpp b/src/coreComponents/physicsSolvers/SolverStatistics.cpp index fe174de612b..4af65d68c92 100644 --- a/src/coreComponents/physicsSolvers/SolverStatistics.cpp +++ b/src/coreComponents/physicsSolvers/SolverStatistics.cpp @@ -38,18 +38,6 @@ SolverStatistics::SolverStatistics( string const & name, Group * const parent ) setApplyDefaultValue( 0 ). setDescription( "Number of time step cuts" ); - registerWrapper( viewKeyStruct::numCurrentOuterLoopIterationsString(), &m_currentNumOuterLoopIterations ). - setApplyDefaultValue( 0 ). - setDescription( "Cumulative number of current outer loop iterations" ); - - registerWrapper( viewKeyStruct::numCurrentNonlinearIterationsString(), &m_currentNumNonlinearIterations ). - setApplyDefaultValue( 0 ). - setDescription( "Cumulative number of current nonlinear iterations" ); - - registerWrapper( viewKeyStruct::numCurrentLinearIterationsString(), &m_currentNumLinearIterations ). - setApplyDefaultValue( 0 ). - setDescription( "Cumulative number of current linear iterations" ); - registerWrapper( viewKeyStruct::numSuccessfulOuterLoopIterationsString(), &m_numSuccessfulOuterLoopIterations ). setApplyDefaultValue( 0 ). setDescription( "Cumulative number of successful outer loop iterations" ); diff --git a/src/coreComponents/physicsSolvers/SolverStatistics.hpp b/src/coreComponents/physicsSolvers/SolverStatistics.hpp index 8bd15139df6..d863c3a36ed 100644 --- a/src/coreComponents/physicsSolvers/SolverStatistics.hpp +++ b/src/coreComponents/physicsSolvers/SolverStatistics.hpp @@ -140,14 +140,6 @@ class SolverStatistics : public dataRepository::Group /// String key for the number of time step cuts static constexpr char const * numTimeStepCutsString() { return "numTimeStepCuts"; } - - /// String key for the current number of outer loop iterations - static constexpr char const * numCurrentOuterLoopIterationsString() { return "numCurrentOuterLoopIterations"; } - /// String key for the current number of nonlinear iterations - static constexpr char const * numCurrentNonlinearIterationsString() { return "numCurrentNonlinearIterations"; } - /// String key for the current number of linear iterations - static constexpr char const * numCurrentLinearIterationsString() { return "numCurrentLinearIterations"; } - /// String key for the successful number of outer loop iterations static constexpr char const * numSuccessfulOuterLoopIterationsString() { return "numSuccessfulOuterLoopIterations"; } /// String key for the successful number of nonlinear iterations From fbf98989df55a09e78386f03b89fffc0a0bf204b Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Tue, 23 Jul 2024 08:56:17 -0700 Subject: [PATCH 47/71] only register region state props once --- .../fluidFlow/wells/CompositionalMultiphaseWell.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 5f62245a882..494c6bc377c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -187,14 +187,6 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); - - - subRegion.registerField< fields::well::pressure >( getName() ); - subRegion.registerField< fields::well::pressure_n >( getName() ); - - subRegion.registerField< fields::well::temperature >( getName() ); - subRegion.registerField< fields::well::temperature_n >( getName() ); - // The resizing of the arrays needs to happen here, before the call to initializePreSubGroups, // to make sure that the dimensions are properly set before the timeHistoryOutput starts its initialization. From e6db741da2520b9569b4261c31bea9c179445985 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Mon, 29 Jul 2024 07:04:25 -0700 Subject: [PATCH 48/71] 1) for shutin wells zero completion perforation rates for clarity in reporting, 2) initialize seg temps with input inj temp, if user specifed surface+inj temp this caused differences with dev for isothermal runs --- .../wells/CompositionalMultiphaseWell.cpp | 18 +++++++++++++----- .../CompositionalMultiphaseWellKernels.cpp | 13 +++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 494c6bc377c..5372455dbe4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -1641,7 +1641,7 @@ void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) { - + PerforationData * const perforationData = subRegion.getPerforationData(); WellControls const & wellControls = getWellControls( subRegion ); if( wellControls.isWellOpen( time_n+ dt ) ) { @@ -1652,9 +1652,6 @@ void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); bool isThermal = fluid.isThermal(); - - PerforationData * const perforationData = subRegion.getPerforationData(); - if( isThermal ) { thermalPerforationFluxKernels:: @@ -1681,7 +1678,18 @@ void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n disableReservoirToWellFlow ); } } - + else + { + // Zero completion flow rate + arrayView2d< real64 > const compPerfRate = perforationData->getField< fields::well::compPerforationRate >(); + for( integer iperf=0; iperfsize(); iperf++ ) + { + for( integer ic = 0; ic < m_numComponents; ++ic ) + { + compPerfRate[iperf][ic] = 0.0; + } + } + } } ); } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp index be09f335c93..8be39397ed2 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.cpp @@ -577,16 +577,9 @@ PresTempCompFracInitializationKernel:: // for an injector, we use the injection stream values else { - if( wellControls.useSurfaceConditions() ) - { - // use surface temperature from injection stream - avgTemp = wellControls.getSurfaceTemperature(); - } - else - { - // use temperature from injection stream - avgTemp = wellControls.getInjectionTemperature(); - } + // use temperature from injection stream + avgTemp = wellControls.getInjectionTemperature(); + // use comp frac from injection stream for( integer ic = 0; ic < numComps; ++ic ) { From 8963ffa07857ec1139a0b1e51ce2b1dd4fd86598 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:11:25 -0700 Subject: [PATCH 49/71] code cleanup - remove partial thermal impl for single phase --- .../fluidFlow/wells/SinglePhaseWell.cpp | 180 ++--------- .../fluidFlow/wells/SinglePhaseWell.hpp | 17 +- .../wells/SinglePhaseWellKernels.hpp | 298 ------------------ 3 files changed, 36 insertions(+), 459 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 4ab45d74428..646206b7a07 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -22,11 +22,9 @@ #include "common/DataTypes.hpp" #include "common/FieldSpecificationOps.hpp" #include "common/TimingMacros.hpp" -#include "common/KernelLaunchSelectors.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" #include "constitutive/fluid/singlefluid/SingleFluidSelector.hpp" -#include "constitutive/fluid/multifluid/Layouts.hpp" #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/WellElementSubRegion.hpp" @@ -36,7 +34,6 @@ #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" -#include "physicsSolvers/fluidFlow/wells/ThermalSinglePhaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" namespace geos @@ -77,13 +74,6 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) GEOS_ERROR_IF( fluidName.empty(), GEOS_FMT( "{}: Fluid model not found on subregion {}", getDataContext(), subRegion.getName() ) ); - subRegion.registerField< fields::well::pressure_n >( getName() ); - subRegion.registerField< fields::well::pressure >( getName() ). - setRestartFlags( RestartFlags::WRITE_AND_READ ); - - subRegion.registerField< fields::well::temperature_n >( getName() ); - subRegion.registerField< fields::well::temperature >( getName() ); - subRegion.registerField< fields::well::connectionRate_n >( getName() ); subRegion.registerField< fields::well::connectionRate >( getName() ); @@ -94,17 +84,9 @@ void SinglePhaseWell::registerDataOnMesh( Group & meshBodies ) WellControls & wellControls = getWellControls( subRegion ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( 2 ); // dP, dT wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentBHP_dPresString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::currentVolRateString() ); - wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentVolRateString() ). - setSizedFromParent( 0 ). - reference().resizeDimension< 0 >( 3 ); // dP, dT, dQ - - wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentVolRate_dPresString() ); wellControls.registerWrapper< real64 >( viewKeyStruct::dCurrentVolRate_dRateString() ); @@ -178,7 +160,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const & dens = fluid.density(); arrayView2d< real64 const > const & dDens_dPres = fluid.dDensity_dPressure(); - arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); + // control data WellControls & wellControls = getWellControls( subRegion ); @@ -188,39 +170,23 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) real64 & currentBHP = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ); - arrayView1d< real64 > const & dCurrentBHP = - wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentBHPString() ); - real64 & dCurrentBHP_dPres = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::dCurrentBHP_dPresString() ); // bring everything back to host, capture the scalars by reference - geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL ) { - integer constexpr IS_THERMAL = ISTHERMAL(); - //using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >; - using Deriv = multifluid::DerivativeOffset; - forAll< serialPolicy >( 1, [ pres, + forAll< serialPolicy >( 1, [pres, dens, dDens_dPres, - dDens_dTemp, wellElemGravCoef, ¤tBHP, - &dCurrentBHP, &dCurrentBHP_dPres, &iwelemRef, &refGravCoef] ( localIndex const ) { - real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef]; - currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * diffGravCoef; - dCurrentBHP[Deriv::dP] = 1.0 + dDens_dPres[iwelemRef][0] * diffGravCoef; - dCurrentBHP_dPres = 1.0 + dDens_dPres[iwelemRef][0] * diffGravCoef; - - if constexpr ( IS_THERMAL ) - { - dCurrentBHP[Deriv::dT] = 1.0 + dDens_dTemp[iwelemRef][0] * diffGravCoef; - } - } ); + currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * ( refGravCoef - wellElemGravCoef[iwelemRef] ); + dCurrentBHP_dPres = 1.0 + dDens_dPres[iwelemRef][0] * ( refGravCoef - wellElemGravCoef[iwelemRef] ); } ); + if( logLevel >= 2 ) { GEOS_LOG_RANK( GEOS_FMT( "{}: The BHP (at the specified reference elevation) is {} Pa", @@ -254,7 +220,7 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const & dens = fluid.density(); arrayView2d< real64 const > const & dDens_dPres = fluid.dDensity_dPressure(); - arrayView2d< real64 const > const & dDens_dTemp = fluid.dDensity_dTemperature(); + // control data WellControls & wellControls = getWellControls( subRegion ); @@ -265,9 +231,6 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi real64 & currentVolRate = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() ); - arrayView1d< real64 > const & dCurrentVolRate = - wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentVolRateString() ); - real64 & dCurrentVolRate_dPres = wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::dCurrentVolRate_dPresString() ); real64 & dCurrentVolRate_dRate = @@ -276,20 +239,16 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL ) { - integer constexpr IS_THERMAL = ISTHERMAL(); - using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >; + // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [fluidWrapper, pres, connRate, dens, dDens_dPres, - dDens_dTemp, &useSurfaceConditions, &surfacePres, ¤tVolRate, - &dCurrentVolRate, &dCurrentVolRate_dPres, &dCurrentVolRate_dRate, &iwelemRef, @@ -322,13 +281,7 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi real64 const densInv = 1.0 / dens[iwelemRef][0]; currentVolRate = connRate[iwelemRef] * densInv; dCurrentVolRate_dPres = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; - dCurrentVolRate[COFFSET_WJ::dP] = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; dCurrentVolRate_dRate = densInv; - dCurrentVolRate[COFFSET_WJ::dQ] = densInv; - if constexpr ( IS_THERMAL ) - { - dCurrentVolRate[COFFSET_WJ::dT] = -( useSurfaceConditions == 0 ) * dDens_dTemp[iwelemRef][0] * currentVolRate * densInv; - } if( logLevel >= 2 && useSurfaceConditions ) { @@ -337,7 +290,6 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi wellControlsName, dens[iwelemRef][0], connRate[iwelemRef], currentVolRate ) ); } - } ); } ); } ); } @@ -391,9 +343,6 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & WellElementSubRegion & subRegion ) { WellControls const & wellControls = getWellControls( subRegion ); - if( time_n <= 0.0 || ( !wellControls.isWellOpen( time_n ) && wellControls.isWellOpen( time_n + dt ) ) ) - { - PerforationData const & perforationData = *subRegion.getPerforationData(); // get the info stored on well elements @@ -455,7 +404,6 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & 0.0, // initialization done at t = 0 wellElemDens, connRate ); - } } ); @@ -484,10 +432,6 @@ void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, [&]( localIndex const, WellElementSubRegion const & subRegion ) { - WellControls const & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time_n + dt ) ) - { - // get a reference to the degree-of-freedom numbers string const wellDofKey = dofManager.getKey( wellElementDofName() ); arrayView1d< globalIndex const > const & wellElemDofNumber = @@ -507,7 +451,6 @@ void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, dt, localMatrix, localRhs ); - } } ); } ); @@ -535,10 +478,7 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, WellElementSubRegion const & subRegion ) { - WellControls & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time_n + dt ) ) - { // get the degrees of freedom numbers, depth, next well elem index string const wellDofKey = dofManager.getKey( wellElementDofName() ); @@ -595,66 +535,21 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, << " from rate constraint to BHP constraint" ); } } - } + } ); } ); } void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, - real64 const & dt, DomainPartition & domain, + real64 const & dt, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - - if( 0 ) - { - string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) - { - - ElementRegionManager const & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { - - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); - SingleFluidBase const & fluid = getConstitutiveModel< SingleFluidBase >( subRegion, fluidName ); - if( isThermal() ) - { - - thermalSinglePhaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - wellElemDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - - } - else - { - singlePhaseWellKernels:: - ElementBasedAssemblyKernelFactory:: - createAndLaunch< parallelDevicePolicy<> >( - dofManager.rankOffset(), - wellElemDofKey, - subRegion, - fluid, - localMatrix, - localRhs ); - } - } ); - } ); - } - else - { + GEOS_UNUSED_VAR(time_n); + GEOS_UNUSED_VAR(dt); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel const & mesh, arrayView1d< string const > const & regionNames ) @@ -672,11 +567,6 @@ void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, arrayView1d< globalIndex const > const wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellElemDofKey ); arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank(); - WellControls & wellControls = getWellControls( subRegion ); - - if( wellControls.isWellOpen( time_n + dt ) ) - { - arrayView1d< real64 const > const wellElemVolume = subRegion.getElementVolume(); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); @@ -695,38 +585,19 @@ void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, wellElemDensity_n, localMatrix, localRhs ); - } - else - { - localIndex rank_offset = dofManager.rankOffset(); - forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( wellElemGhostRank[ei] < 0 ) - { - - globalIndex const dofIndex = wellElemDofNumber[ei]; - localIndex const localRow = dofIndex - rank_offset; - - - real64 unity = 1.0; - for( integer i=0; i < m_numDofPerWellElement; i++ ) - { - globalIndex const rindex = wellElemDofNumber[ei] + i; - globalIndex const cindex = localRow+1; - localMatrix.template addToRow< serialAtomic >( rindex, - &cindex, - &unity, - 1 ); - localRhs[cindex] = 0.0; - } - } - } ); - - } - } ); } ); - } + } ); + // then assemble the volume balance equations + assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); +} + +void SinglePhaseWell::assembleVolumeBalanceTerms( DomainPartition const & GEOS_UNUSED_PARAM( domain ), + DofManager const & GEOS_UNUSED_PARAM( dofManager ), + CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ), + arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) +{ + // not implemented for single phase flow } void SinglePhaseWell::shutDownWell( real64 const time_n, @@ -823,10 +694,6 @@ void SinglePhaseWell::computePerforationRates( real64 const & time_n, mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) - { - - WellControls const & wellControls = getWellControls( subRegion ); - if( wellControls.isWellOpen( time_n + dt ) ) { // get the well data @@ -888,7 +755,6 @@ void SinglePhaseWell::computePerforationRates( real64 const & time_n, resElementIndex, perfRate, dPerfRate_dPres ); - } } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 726e4c99bfe..a1cc9f3ff4a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -178,7 +178,7 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - void assembleFluxTerms( real64 const & time_n, + virtual void assembleFluxTerms( real64 const & time_n, real64 const & dt, DomainPartition & domain, DofManager const & dofManager, @@ -192,12 +192,23 @@ class SinglePhaseWell : public WellSolverBase * @param matrix the system matrix * @param rhs the system right-hand side vector */ - void assembleAccumulationTerms( real64 const & time_n, + virtual void assembleAccumulationTerms( real64 const & time_n, real64 const & dt, DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) override; + /** + * @brief assembles the volume balance terms for all well elements + * @param domain the physical domain object + * @param dofManager degree-of-freedom manager associated with the linear system + * @param matrix the system matrix + * @param rhs the system right-hand side vector + */ + void assembleVolumeBalanceTerms( DomainPartition const & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) ; /** * @brief assembles the pressure relations at all connections between well elements except at the well head @@ -238,11 +249,9 @@ class SinglePhaseWell : public WellSolverBase // control data (not registered on the mesh) static constexpr char const * currentBHPString() { return "currentBHP"; } - static constexpr char const * dCurrentBHPString() { return "dCurrentBHP"; } static constexpr char const * dCurrentBHP_dPresString() { return "dCurrentBHP_dPres"; } static constexpr char const * currentVolRateString() { return "currentVolumetricRate"; } - static constexpr char const * dCurrentVolRateString() { return "dCurrentVolumetricRate"; } static constexpr char const * dCurrentVolRate_dPresString() { return "dCurrentVolumetricRate_dPres"; } static constexpr char const * dCurrentVolRate_dRateString() { return "dCurrentVolumetricRate_dRate"; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp index 1bd8c34f7e4..12767869b48 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp @@ -36,26 +36,6 @@ namespace geos namespace singlePhaseWellKernels { - -template< integer IS_THERMAL > -struct ColOffset_WellJac {}; - - -template<> -struct ColOffset_WellJac< 0 > -{ - static constexpr integer dP = 0; - static constexpr integer dQ = 1; -}; -template<> -struct ColOffset_WellJac< 1 > -{ - static constexpr integer dP = 0; - static constexpr integer dQ = 1; - static constexpr integer dT = 2; -}; - - // tag to access well and reservoir elements in perforation rates computation struct SubRegionTag { @@ -521,284 +501,6 @@ struct SolutionCheckKernel } }; -/******************************** ElementBasedAssemblyKernel ********************************/ - -/** - * @class ElementBasedAssemblyKernel - * @tparam NUM_DOF number of degrees of freedom - * @brief Define the interface for the assembly kernel in charge of accumulation and volume balance - */ -template< integer NUM_DOF > -class ElementBasedAssemblyKernel -{ -public: - using ROFFSET = singlePhaseWellKernels::RowOffset; - using COFFSET = singlePhaseWellKernels::ColOffset; - - /// Compute time value for the number of degrees of freedom - static constexpr integer numDof = NUM_DOF; - - /// Compute time value for the number of equations - static constexpr integer numEqn = NUM_DOF; - - /** - * @brief Constructor - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - ElementBasedAssemblyKernel( globalIndex const rankOffset, - string const dofKey, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : - m_rankOffset( rankOffset ), - m_wellElemDofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), - m_elemGhostRank( subRegion.ghostRank() ), - m_wellElemVolume( subRegion.getElementVolume() ), - m_wellElemDensity( fluid.density() ), - m_wellElemDensity_n( fluid.density_n() ), - - m_dWellElemDensity_dPressure( fluid.dDensity_dPressure() ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - // volume information (used by both accumulation and volume balance) - real64 volume = 0.0; - real64 density = 0.0; - real64 density_n = 0.0; - real64 dDensity_dPres = 0.0; - - - // Residual information - - /// Index of the local row corresponding to this element - localIndex localRow = -1; - - /// Indices of the matrix rows/columns corresponding to the dofs in this element - globalIndex dofIndices[numDof]{}; - globalIndex eqnRowIndices[numDof]{}; - globalIndex dofColIndices[numDof]{}; - - /// C-array storage for the element local residual vector (all equations ) - real64 localResidual[numDof]{}; - - /// C-array storage for the element local Jacobian matrix (all equations , all dofs) - real64 localJacobian[numDof][numDof]{}; - - }; - /** - * @brief Getter for the ghost rank of an element - * @param[in] ei the element index - * @return the ghost rank of the element - */ - GEOS_HOST_DEVICE - integer elemGhostRank( localIndex const ei ) const - { return m_elemGhostRank( ei ); } - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] ei the element index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - // initialize the volume - stack.volume = m_wellElemVolume[ei]; - stack.density = m_wellElemDensity[ei][0]; - stack.density_n = m_wellElemDensity_n[ei][0]; - stack.dDensity_dPres = m_dWellElemDensity_dPressure[ei][0]; - - // set row index and degrees of freedom indices for this element (mass + vol bal) - for( integer ic = 0; ic < numDof; ++ic ) - { - stack.eqnRowIndices[ic] = m_wellElemDofNumber[ei] + ic - m_rankOffset; - } - - // set DOF col indices for this block ( mass + vol bal) - for( integer idof = 0; idof < numDof; ++idof ) - { - stack.dofColIndices[idof] = m_wellElemDofNumber[ei] + idof; - } - - for( integer jc = 0; jc < numDof; ++jc ) - { - stack.localResidual[jc] = 0.0; - for( integer ic = 0; ic < numDof; ++ic ) - { - stack.localJacobian[jc][ic] = 0.0; - } - - } - - } - - - /** - * @brief Compute the local accumulation contributions to the residual and Jacobian - * @tparam FUNC the type of the function that can be used to customize the kernel - * @param[in] ei the element index - * @param[inout] stack the stack variables - * @param[in] phaseAmountKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const iwelem, - StackVariables & stack, - FUNC && KernelOp = NoOpFunc{} ) const - { - GEOS_UNUSED_VAR( iwelem ); - //localIndex const eqnRowIndex = m_wellElemDofNumber[iwelem] + ROFFSET::MASSBAL - m_rankOffset; - //globalIndex const presDofColIndex = m_wellElemDofNumber[iwelem] + COFFSET::DPRES; - - stack.localResidual[0] = stack.volume * ( stack.density - stack.density_n ); - stack.localJacobian[0][1] = stack.volume * stack.dDensity_dPres; - - KernelOp(); - // check zero diagonal (works only in debug) - /* - for( integer ic = 0; ic < numComp; ++ic ) - { - GEOS_ASSERT_MSG ( LvArray::math::abs( stack.localJacobian[ic][ic] ) > minDensForDivision, - GEOS_FMT( "Zero diagonal in Jacobian: equation {}, value = {}", ic, stack.localJacobian[ic][ic] ) ); - } - */ - } - - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const GEOS_UNUSED_PARAM( ei ), - StackVariables & stack ) const - { - - // add contribution to residual and jacobian into: - // - mass bal - // - pressure eqn - // - energy if thermal - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - - for( integer i = 0; i < NUM_DOF; ++i ) - { - m_localRhs[stack.eqnRowIndices[i]] += stack.localResidual[i]; - m_localMatrix.template addToRow< serialAtomic >( stack.eqnRowIndices[i], - stack.dofColIndices, - stack.localJacobian[i], - numDof ); - } - - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numElems the number of elements - * @param[inout] kernelComponent the kernel component providing access to setup/compute/complete functions and stack variables - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const iwelem ) - { - if( kernelComponent.elemGhostRank( iwelem ) >= 0 ) - { - return; - } - typename KERNEL_TYPE::StackVariables stack; - kernelComponent.setup( iwelem, stack ); - kernelComponent.computeAccumulation( iwelem, stack ); - kernelComponent.complete( iwelem, stack ); - - } ); - } - -protected: - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// View on the dof numbers - arrayView1d< globalIndex const > const m_wellElemDofNumber; - - /// View on the ghost ranks - arrayView1d< integer const > const m_elemGhostRank; - - /// View on the element volumes - arrayView1d< real64 const > const m_wellElemVolume; - - /// Views on the densities - arrayView2d< real64 const > const m_wellElemDensity; - arrayView2d< real64 const > const m_wellElemDensity_n; - arrayView2d< real64 const > const m_dWellElemDensity_dPressure; - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - - -}; - - -/** - * @class ElementBasedAssemblyKernelFactory - */ -class ElementBasedAssemblyKernelFactory -{ -public: - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey the string key to retrieve the degress of freedom numbers - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY > - static void - createAndLaunch( globalIndex const rankOffset, - string const dofKey, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_DOF = 2; - ElementBasedAssemblyKernel< NUM_DOF > - kernel( rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs ); - ElementBasedAssemblyKernel< NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< NUM_DOF > >( subRegion.size(), kernel ); - - } -}; } // end namespace singlePhaseWellKernels } // end namespace geos From 25d8e2b04f2984f3018a0e1aa5a4e7a7738c67c5 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:59:37 -0700 Subject: [PATCH 50/71] run non-automatic uncrusty --- .../fluidFlow/wells/SinglePhaseWell.cpp | 558 +++++++++--------- .../fluidFlow/wells/SinglePhaseWell.hpp | 24 +- 2 files changed, 291 insertions(+), 291 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 646206b7a07..94f3cd0de33 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -175,14 +175,14 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) // bring everything back to host, capture the scalars by reference forAll< serialPolicy >( 1, [pres, - dens, - dDens_dPres, - wellElemGravCoef, - ¤tBHP, - &dCurrentBHP_dPres, - &iwelemRef, - &refGravCoef] ( localIndex const ) - { + dens, + dDens_dPres, + wellElemGravCoef, + ¤tBHP, + &dCurrentBHP_dPres, + &iwelemRef, + &refGravCoef] ( localIndex const ) + { currentBHP = pres[iwelemRef] + dens[iwelemRef][0] * ( refGravCoef - wellElemGravCoef[iwelemRef] ); dCurrentBHP_dPres = 1.0 + dDens_dPres[iwelemRef][0] * ( refGravCoef - wellElemGravCoef[iwelemRef] ); } ); @@ -240,56 +240,56 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - // bring everything back to host, capture the scalars by reference - forAll< serialPolicy >( 1, [fluidWrapper, - pres, - connRate, - dens, - dDens_dPres, - &useSurfaceConditions, - &surfacePres, - ¤tVolRate, - &dCurrentVolRate_dPres, - &dCurrentVolRate_dRate, - &iwelemRef, - &logLevel, - &wellControlsName] ( localIndex const ) - { - // We need to evaluate the density as follows: - // - Surface conditions: using the surface pressure provided by the user - // - Reservoir conditions: using the pressure in the top element + // bring everything back to host, capture the scalars by reference + forAll< serialPolicy >( 1, [fluidWrapper, + pres, + connRate, + dens, + dDens_dPres, + &useSurfaceConditions, + &surfacePres, + ¤tVolRate, + &dCurrentVolRate_dPres, + &dCurrentVolRate_dRate, + &iwelemRef, + &logLevel, + &wellControlsName] ( localIndex const ) + { + // We need to evaluate the density as follows: + // - Surface conditions: using the surface pressure provided by the user + // - Reservoir conditions: using the pressure in the top element - if( useSurfaceConditions ) + if( useSurfaceConditions ) + { + // we need to compute the surface density + fluidWrapper.update( iwelemRef, 0, surfacePres ); + if( logLevel >= 2 ) { - // we need to compute the surface density - fluidWrapper.update( iwelemRef, 0, surfacePres ); - if( logLevel >= 2 ) - { - GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa", - wellControlsName, surfacePres ) ); + GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa", + wellControlsName, surfacePres ) ); #ifdef GEOS_USE_HIP - GEOS_UNUSED_VAR( wellControlsName ); + GEOS_UNUSED_VAR( wellControlsName ); #endif - } - } - else - { - real64 const refPres = pres[iwelemRef]; - fluidWrapper.update( iwelemRef, 0, refPres ); } + } + else + { + real64 const refPres = pres[iwelemRef]; + fluidWrapper.update( iwelemRef, 0, refPres ); + } - real64 const densInv = 1.0 / dens[iwelemRef][0]; - currentVolRate = connRate[iwelemRef] * densInv; - dCurrentVolRate_dPres = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; - dCurrentVolRate_dRate = densInv; + real64 const densInv = 1.0 / dens[iwelemRef][0]; + currentVolRate = connRate[iwelemRef] * densInv; + dCurrentVolRate_dPres = -( useSurfaceConditions == 0 ) * dDens_dPres[iwelemRef][0] * currentVolRate * densInv; + dCurrentVolRate_dRate = densInv; - if( logLevel >= 2 && useSurfaceConditions ) - { - GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} kg/sm3. \n" - "The total rate is {} kg/s, which corresponds to a total surface volumetric rate of {} sm3/s", - wellControlsName, dens[iwelemRef][0], - connRate[iwelemRef], currentVolRate ) ); - } + if( logLevel >= 2 && useSurfaceConditions ) + { + GEOS_LOG_RANK( GEOS_FMT( "{}: The total fluid density at surface conditions is {} kg/sm3. \n" + "The total rate is {} kg/s, which corresponds to a total surface volumetric rate of {} sm3/s", + wellControlsName, dens[iwelemRef][0], + connRate[iwelemRef], currentVolRate ) ); + } } ); } ); } @@ -343,67 +343,67 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & WellElementSubRegion & subRegion ) { WellControls const & wellControls = getWellControls( subRegion ); - PerforationData const & perforationData = *subRegion.getPerforationData(); - - // get the info stored on well elements - arrayView1d< real64 const > const wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); - - // get well primary variables on well elements - arrayView1d< real64 > const wellElemPressure = - subRegion.getField< fields::well::pressure >(); - arrayView1d< real64 > const connRate = - subRegion.getField< fields::well::connectionRate >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = - perforationData.getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = - perforationData.getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = - perforationData.getField< fields::perforation::reservoirElementIndex >(); - - arrayView1d< real64 const > const & perfGravCoef = - perforationData.getField< fields::well::gravityCoefficient >(); - - // TODO: change the way we access the flowSolver here - SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() ); - PresInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( meshLevel.getElemManager(), flowSolver.getName() ); - PresInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( meshLevel.getElemManager(), flowSolver.getName() ); - - // 1) Loop over all perforations to compute an average density - // 2) Initialize the reference pressure - // 3) Estimate the pressures in the well elements using the average density - PresInitializationKernel:: - launch( perforationData.size(), - subRegion.size(), - perforationData.getNumPerforationsGlobal(), - wellControls, - 0.0, // initialization done at t = 0 - resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), - resSingleFluidAccessors.get( fields::singlefluid::density{} ), - resElementRegion, - resElementSubRegion, - resElementIndex, - perfGravCoef, - wellElemGravCoef, - wellElemPressure ); - - // 4) Recompute the pressure-dependent properties - // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState) - // to better initialize the rates - updateSubRegionState( subRegion ); - - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); - arrayView2d< real64 const > const & wellElemDens = fluid.density(); - - // 5) Estimate the well rates - RateInitializationKernel::launch( subRegion.size(), - wellControls, - 0.0, // initialization done at t = 0 - wellElemDens, - connRate ); + PerforationData const & perforationData = *subRegion.getPerforationData(); + + // get the info stored on well elements + arrayView1d< real64 const > const wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); + + // get well primary variables on well elements + arrayView1d< real64 > const wellElemPressure = + subRegion.getField< fields::well::pressure >(); + arrayView1d< real64 > const connRate = + subRegion.getField< fields::well::connectionRate >(); + + // get the element region, subregion, index + arrayView1d< localIndex const > const resElementRegion = + perforationData.getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const resElementSubRegion = + perforationData.getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const resElementIndex = + perforationData.getField< fields::perforation::reservoirElementIndex >(); + + arrayView1d< real64 const > const & perfGravCoef = + perforationData.getField< fields::well::gravityCoefficient >(); + + // TODO: change the way we access the flowSolver here + SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() ); + PresInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( meshLevel.getElemManager(), flowSolver.getName() ); + PresInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( meshLevel.getElemManager(), flowSolver.getName() ); + + // 1) Loop over all perforations to compute an average density + // 2) Initialize the reference pressure + // 3) Estimate the pressures in the well elements using the average density + PresInitializationKernel:: + launch( perforationData.size(), + subRegion.size(), + perforationData.getNumPerforationsGlobal(), + wellControls, + 0.0, // initialization done at t = 0 + resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), + resSingleFluidAccessors.get( fields::singlefluid::density{} ), + resElementRegion, + resElementSubRegion, + resElementIndex, + perfGravCoef, + wellElemGravCoef, + wellElemPressure ); + + // 4) Recompute the pressure-dependent properties + // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState) + // to better initialize the rates + updateSubRegionState( subRegion ); + + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); + arrayView2d< real64 const > const & wellElemDens = fluid.density(); + + // 5) Estimate the well rates + RateInitializationKernel::launch( subRegion.size(), + wellControls, + 0.0, // initialization done at t = 0 + wellElemDens, + connRate ); } ); @@ -432,25 +432,25 @@ void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, [&]( localIndex const, WellElementSubRegion const & subRegion ) { - // get a reference to the degree-of-freedom numbers - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); - - // get a reference to the primary variables on well elements - arrayView1d< real64 const > const connRate = - subRegion.getField< fields::well::connectionRate >(); - - FluxKernel::launch( subRegion.size(), - dofManager.rankOffset(), - wellElemDofNumber, - nextWellElemIndex, - connRate, - dt, - localMatrix, - localRhs ); + // get a reference to the degree-of-freedom numbers + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< localIndex const > const & nextWellElemIndex = + subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); + + // get a reference to the primary variables on well elements + arrayView1d< real64 const > const connRate = + subRegion.getField< fields::well::connectionRate >(); + + FluxKernel::launch( subRegion.size(), + dofManager.rankOffset(), + wellElemDofNumber, + nextWellElemIndex, + connRate, + dt, + localMatrix, + localRhs ); } ); } ); @@ -480,61 +480,61 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, WellControls & wellControls = getWellControls( subRegion ); - // get the degrees of freedom numbers, depth, next well elem index - string const wellDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const & wellElemDofNumber = - subRegion.getReference< array1d< globalIndex > >( wellDofKey ); - arrayView1d< real64 const > const & wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const & nextWellElemIndex = - subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); - - // get primary variables on well elements - arrayView1d< real64 const > const & wellElemPressure = - subRegion.getField< fields::well::pressure >(); - - // get well constitutive data - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); - arrayView2d< real64 const > const & wellElemDensity = fluid.density(); - arrayView2d< real64 const > const & dWellElemDensity_dPres = fluid.dDensity_dPressure(); - - localIndex const controlHasSwitched = - PressureRelationKernel::launch( subRegion.size(), - dofManager.rankOffset(), - subRegion.isLocallyOwned(), - subRegion.getTopWellElementIndex(), - wellControls, - time_n + dt, // controls evaluated with BHP/rate of the end of the time interval - wellElemDofNumber, - wellElemGravCoef, - nextWellElemIndex, - wellElemPressure, - wellElemDensity, - dWellElemDensity_dPres, - localMatrix, - localRhs ); - - if( controlHasSwitched == 1 ) + // get the degrees of freedom numbers, depth, next well elem index + string const wellDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const & wellElemDofNumber = + subRegion.getReference< array1d< globalIndex > >( wellDofKey ); + arrayView1d< real64 const > const & wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); + arrayView1d< localIndex const > const & nextWellElemIndex = + subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() ); + + // get primary variables on well elements + arrayView1d< real64 const > const & wellElemPressure = + subRegion.getField< fields::well::pressure >(); + + // get well constitutive data + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); + arrayView2d< real64 const > const & wellElemDensity = fluid.density(); + arrayView2d< real64 const > const & dWellElemDensity_dPres = fluid.dDensity_dPressure(); + + localIndex const controlHasSwitched = + PressureRelationKernel::launch( subRegion.size(), + dofManager.rankOffset(), + subRegion.isLocallyOwned(), + subRegion.getTopWellElementIndex(), + wellControls, + time_n + dt, // controls evaluated with BHP/rate of the end of the time interval + wellElemDofNumber, + wellElemGravCoef, + nextWellElemIndex, + wellElemPressure, + wellElemDensity, + dWellElemDensity_dPres, + localMatrix, + localRhs ); + + if( controlHasSwitched == 1 ) + { + // Note: if BHP control is not viable, we switch to TOTALVOLRATE + // if TOTALVOLRATE is not viable, we switch to BHP + + real64 const timeAtEndOfStep = time_n + dt; + + if( wellControls.getControl() == WellControls::Control::BHP ) { - // Note: if BHP control is not viable, we switch to TOTALVOLRATE - // if TOTALVOLRATE is not viable, we switch to BHP - - real64 const timeAtEndOfStep = time_n + dt; - - if( wellControls.getControl() == WellControls::Control::BHP ) - { - wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from BHP constraint to rate constraint" ); - } - else - { - wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); - GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() - << " from rate constraint to BHP constraint" ); - } + wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() + << " from BHP constraint to rate constraint" ); } + else + { + wellControls.switchToBHPControl( wellControls.getTargetBHP( timeAtEndOfStep ) ); + GEOS_LOG_LEVEL( 1, "Control switch for well " << subRegion.getName() + << " from rate constraint to BHP constraint" ); + } + } } ); } ); @@ -542,53 +542,53 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n, void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n, real64 const & dt, - DomainPartition & domain, + DomainPartition & domain, DofManager const & dofManager, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - GEOS_UNUSED_VAR(time_n); - GEOS_UNUSED_VAR(dt); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel const & mesh, - arrayView1d< string const > const & regionNames ) + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel const & mesh, + arrayView1d< string const > const & regionNames ) + { + + ElementRegionManager const & elemManager = mesh.getElemManager(); + + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, + [&]( localIndex const, + WellElementSubRegion const & subRegion ) { - ElementRegionManager const & elemManager = mesh.getElemManager(); + // get a reference to the degree-of-freedom numbers + string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); + arrayView1d< globalIndex const > const wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellElemDofKey ); + arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank(); - elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, - [&]( localIndex const, - WellElementSubRegion const & subRegion ) - { + arrayView1d< real64 const > const wellElemVolume = subRegion.getElementVolume(); - // get a reference to the degree-of-freedom numbers - string const wellElemDofKey = dofManager.getKey( wellElementDofName() ); - arrayView1d< globalIndex const > const wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellElemDofKey ); - arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank(); - - arrayView1d< real64 const > const wellElemVolume = subRegion.getElementVolume(); - - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); - arrayView2d< real64 const > const wellElemDensity = fluid.density(); - arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); - arrayView2d< real64 const > const wellElemDensity_n = fluid.density_n(); - - AccumulationKernel::launch( subRegion.size(), - dofManager.rankOffset(), - wellElemDofNumber, - wellElemGhostRank, - wellElemVolume, - wellElemDensity, - dWellElemDensity_dPres, - wellElemDensity_n, - localMatrix, - localRhs ); + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); + arrayView2d< real64 const > const wellElemDensity = fluid.density(); + arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); + arrayView2d< real64 const > const wellElemDensity_n = fluid.density_n(); + + AccumulationKernel::launch( subRegion.size(), + dofManager.rankOffset(), + wellElemDofNumber, + wellElemGhostRank, + wellElemVolume, + wellElemDensity, + dWellElemDensity_dPres, + wellElemDensity_n, + localMatrix, + localRhs ); } ); } ); - // then assemble the volume balance equations + // then assemble the volume balance equations assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs ); } @@ -694,67 +694,67 @@ void SinglePhaseWell::computePerforationRates( real64 const & time_n, mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) - { + { + + // get the well data + PerforationData * const perforationData = subRegion.getPerforationData(); + + // get the degrees of freedom and depth + arrayView1d< real64 const > const wellElemGravCoef = + subRegion.getField< fields::well::gravityCoefficient >(); - // get the well data - PerforationData * const perforationData = subRegion.getPerforationData(); - - // get the degrees of freedom and depth - arrayView1d< real64 const > const wellElemGravCoef = - subRegion.getField< fields::well::gravityCoefficient >(); - - // get well primary variables on well elements - arrayView1d< real64 const > const wellElemPressure = - subRegion.getField< fields::well::pressure >(); - - // get well constitutive data - string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const wellElemDensity = fluid.density(); - arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); - arrayView2d< real64 const > const wellElemViscosity = fluid.viscosity(); - arrayView2d< real64 const > const dWellElemViscosity_dPres = fluid.dViscosity_dPressure(); - - // get well variables on perforations - arrayView1d< real64 const > const perfGravCoef = - perforationData->getField< fields::well::gravityCoefficient >(); - arrayView1d< localIndex const > const perfWellElemIndex = - perforationData->getField< fields::perforation::wellElementIndex >(); - arrayView1d< real64 const > const perfTransmissibility = - perforationData->getField< fields::perforation::wellTransmissibility >(); - - arrayView1d< real64 > const perfRate = - perforationData->getField< fields::well::perforationRate >(); - arrayView2d< real64 > const dPerfRate_dPres = - perforationData->getField< fields::well::dPerforationRate_dPres >(); - - // get the element region, subregion, index - arrayView1d< localIndex const > const resElementRegion = - perforationData->getField< fields::perforation::reservoirElementRegion >(); - arrayView1d< localIndex const > const resElementSubRegion = - perforationData->getField< fields::perforation::reservoirElementSubRegion >(); - arrayView1d< localIndex const > const resElementIndex = - perforationData->getField< fields::perforation::reservoirElementIndex >(); - - PerforationKernel::launch( perforationData->size(), - resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), - resSingleFluidAccessors.get( fields::singlefluid::density{} ), - resSingleFluidAccessors.get( fields::singlefluid::dDensity_dPressure{} ), - resSingleFluidAccessors.get( fields::singlefluid::viscosity{} ), - resSingleFluidAccessors.get( fields::singlefluid::dViscosity_dPressure{} ), - wellElemGravCoef, - wellElemPressure, - wellElemDensity, - dWellElemDensity_dPres, - wellElemViscosity, - dWellElemViscosity_dPres, - perfGravCoef, - perfWellElemIndex, - perfTransmissibility, - resElementRegion, - resElementSubRegion, - resElementIndex, - perfRate, - dPerfRate_dPres ); + // get well primary variables on well elements + arrayView1d< real64 const > const wellElemPressure = + subRegion.getField< fields::well::pressure >(); + + // get well constitutive data + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); + SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); arrayView2d< real64 const > const wellElemDensity = fluid.density(); + arrayView2d< real64 const > const dWellElemDensity_dPres = fluid.dDensity_dPressure(); + arrayView2d< real64 const > const wellElemViscosity = fluid.viscosity(); + arrayView2d< real64 const > const dWellElemViscosity_dPres = fluid.dViscosity_dPressure(); + + // get well variables on perforations + arrayView1d< real64 const > const perfGravCoef = + perforationData->getField< fields::well::gravityCoefficient >(); + arrayView1d< localIndex const > const perfWellElemIndex = + perforationData->getField< fields::perforation::wellElementIndex >(); + arrayView1d< real64 const > const perfTransmissibility = + perforationData->getField< fields::perforation::wellTransmissibility >(); + + arrayView1d< real64 > const perfRate = + perforationData->getField< fields::well::perforationRate >(); + arrayView2d< real64 > const dPerfRate_dPres = + perforationData->getField< fields::well::dPerforationRate_dPres >(); + + // get the element region, subregion, index + arrayView1d< localIndex const > const resElementRegion = + perforationData->getField< fields::perforation::reservoirElementRegion >(); + arrayView1d< localIndex const > const resElementSubRegion = + perforationData->getField< fields::perforation::reservoirElementSubRegion >(); + arrayView1d< localIndex const > const resElementIndex = + perforationData->getField< fields::perforation::reservoirElementIndex >(); + + PerforationKernel::launch( perforationData->size(), + resSinglePhaseFlowAccessors.get( fields::flow::pressure{} ), + resSingleFluidAccessors.get( fields::singlefluid::density{} ), + resSingleFluidAccessors.get( fields::singlefluid::dDensity_dPressure{} ), + resSingleFluidAccessors.get( fields::singlefluid::viscosity{} ), + resSingleFluidAccessors.get( fields::singlefluid::dViscosity_dPressure{} ), + wellElemGravCoef, + wellElemPressure, + wellElemDensity, + dWellElemDensity_dPres, + wellElemViscosity, + dWellElemViscosity_dPres, + perfGravCoef, + perfWellElemIndex, + perfTransmissibility, + resElementRegion, + resElementSubRegion, + resElementIndex, + perfRate, + dPerfRate_dPres ); } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index a1cc9f3ff4a..15df41a2e83 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -179,11 +179,11 @@ class SinglePhaseWell : public WellSolverBase * @param rhs the system right-hand side vector */ virtual void assembleFluxTerms( real64 const & time_n, - real64 const & dt, - DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; + real64 const & dt, + DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the accumulation term for all the well elements @@ -193,10 +193,10 @@ class SinglePhaseWell : public WellSolverBase * @param rhs the system right-hand side vector */ virtual void assembleAccumulationTerms( real64 const & time_n, - real64 const & dt, DomainPartition & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) override; + real64 const & dt, DomainPartition & domain, + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) override; /** * @brief assembles the volume balance terms for all well elements @@ -206,9 +206,9 @@ class SinglePhaseWell : public WellSolverBase * @param rhs the system right-hand side vector */ void assembleVolumeBalanceTerms( DomainPartition const & domain, - DofManager const & dofManager, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) ; + DofManager const & dofManager, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); /** * @brief assembles the pressure relations at all connections between well elements except at the well head From eee00a38554c498378a6f838009eb47657cb2fd5 Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Tue, 30 Jul 2024 11:06:28 -0700 Subject: [PATCH 51/71] one more time --- .../physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 94f3cd0de33..e5eb433fab5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -330,7 +330,8 @@ real64 SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & time_n, real64 const & dt ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); // loop over the wells forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & meshLevel, @@ -418,7 +419,8 @@ void SinglePhaseWell::assembleFluxTerms( real64 const & time_n, arrayView1d< real64 > const & localRhs ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); // loop over the wells forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -681,7 +683,8 @@ void SinglePhaseWell::computePerforationRates( real64 const & time_n, real64 const & dt, DomainPartition & domain ) { GEOS_MARK_FUNCTION; - + GEOS_UNUSED_VAR( time_n ); + GEOS_UNUSED_VAR( dt ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, arrayView1d< string const > const & regionNames ) From 11d1d80337c67a8c392ffeaf2b3503c41aaae4a8 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Thu, 1 Aug 2024 13:37:34 -0700 Subject: [PATCH 52/71] revert single phase well initialization to dev ver, fix will be added in different push, compo already has fix(call initialization for wells that become active at t > 0) --- .../physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index e5eb433fab5..284058afa30 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -332,6 +332,13 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & GEOS_MARK_FUNCTION; GEOS_UNUSED_VAR( time_n ); GEOS_UNUSED_VAR( dt ); + // different functionality than for compositional + // compositional has better treatment of well initialization in cases where well starts later in sim + // logic will be incorporated into single phase in different push + if( time_n > 0 ) + { + return; + } // loop over the wells forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & meshLevel, From c51952f920b38b455d2e040c6d87d0ba2b51bbf1 Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Mon, 5 Aug 2024 07:58:17 -0700 Subject: [PATCH 53/71] restructure for GPU reqs --- .../wells/PerforationFluxKernels.hpp | 299 +++++++++--------- 1 file changed, 145 insertions(+), 154 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index c533bf3f45d..db71efee6bd 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -51,8 +51,6 @@ struct NoOpStuct namespace isothermalPerforationFluxKernels { -using namespace constitutive; - /******************************** PerforationFluxKernel ********************************/ @@ -79,7 +77,7 @@ class PerforationFluxKernel fields::flow::dGlobalCompFraction_dGlobalCompDensity >; using MultiFluidAccessors = - StencilMaterialAccessors< MultiFluidBase, + StencilMaterialAccessors< constitutive::MultiFluidBase, fields::multifluid::phaseDensity, fields::multifluid::dPhaseDensity, fields::multifluid::phaseViscosity, @@ -88,7 +86,7 @@ class PerforationFluxKernel fields::multifluid::dPhaseCompFraction >; using RelPermAccessors = - StencilMaterialAccessors< RelativePermeabilityBase, + StencilMaterialAccessors< constitutive::RelativePermeabilityBase, fields::relperm::phaseRelPerm, fields::relperm::dPhaseRelPerm_dPhaseVolFraction >; @@ -151,11 +149,11 @@ class PerforationFluxKernel }; - template< typename STRUCT = NoOpFunc > + template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE inline void - computeFlux( localIndex const iperf, STRUCT && stack= NoOpFunc{} ) const + computeFlux( localIndex const iperf, FUNC && fluxKernelOp= NoOpFunc {} ) const { // get the index of the reservoir elem localIndex const er = m_resElementRegion[iperf]; @@ -165,8 +163,8 @@ class PerforationFluxKernel // get the index of the well elem localIndex const iwelem = m_perfWellElemIndex[iperf]; - using Deriv = multifluid::DerivativeOffset; - using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + using Deriv = constitutive::multifluid::DerivativeOffset; + using CP_Deriv = constitutive::multifluid::DerivativeOffsetC< NC, IS_THERMAL >; // local working variables and arrays real64 pres[2]{}; @@ -195,18 +193,7 @@ class PerforationFluxKernel } } } - if constexpr (IS_THERMAL ) - { - // initialize outputs - stack.m_energyPerfFlux[iperf]=0; - for( integer ke = 0; ke < 2; ++ke ) - { - for( integer i = 0; i < CP_Deriv::nDer; ++i ) - { - stack.m_dEnergyPerfFlux[iperf][ke][i]=0; - } - } - } + // Step 2: copy the variables from the reservoir and well element // a) get reservoir variables @@ -361,36 +348,11 @@ class PerforationFluxKernel m_dCompPerfRate[iperf][TAG::WELL][ic][jc] += dFlux[TAG::WELL][jc] * m_resPhaseCompFrac[er][esr][ei][0][ip][ic]; } } - if constexpr ( IS_THERMAL ) { - real64 const res_enthalpy = stack.m_resPhaseEnthalpy[er][esr][ei][0][ip]; - - stack.m_energyPerfFlux[iperf] += flux * res_enthalpy; - - // energy equation derivatives WRT res P & T - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * res_enthalpy + - flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * res_enthalpy + - flux * stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; - // energy equation derivatives WRT well P - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * res_enthalpy; - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * res_enthalpy; - - - // energy equation derivatives WRT reservoir dens - real64 dProp_dC[numComp]{}; - applyChainRule( NC, - m_dResCompFrac_dCompDens[er][esr][ei], - stack.m_dResPhaseEnthalpy[er][esr][ei][0][ip], - dProp_dC, - Deriv::dC ); - - for( integer jc = 0; jc < NC; ++jc ) - { - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dC+jc] += flux * dProp_dC[jc]; - } + fluxKernelOp( iwelem, er, esr, ei, ip, potDiff, flux, dFlux ); } + } // end resevoir is upstream phase loop } @@ -514,54 +476,9 @@ class PerforationFluxKernel } if constexpr ( IS_THERMAL ) { - for( integer ip = 0; ip < NP; ++ip ) - { - bool const phaseExists = stack.m_wellElemPhaseFrac[iwelem][0][ip] > 0.0; - if( !phaseExists ) - continue; - double pflux = stack.m_wellElemPhaseFrac[iwelem][0][ip]*flux; - real64 const wellelem_enthalpy = stack.m_wellElemPhaseEnthalpy[iwelem][0][ip]; - stack.m_energyPerfFlux[iperf] += pflux * wellelem_enthalpy; - - // energy equation derivatives WRT res P & T - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy; - stack.m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy; - - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy - + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dP] - + pflux * wellelem_enthalpy * stack.m_dPhaseFrac[iwelem][0][ip][Deriv::dP]; - stack.m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy - + pflux * stack.m_dWellElemPhaseEnthalpy[iwelem][0][ip][Deriv::dT] - + pflux * wellelem_enthalpy * stack.m_dPhaseFrac[iwelem][0][ip][Deriv::dT]; - - //energy e - real64 dPVF_dC[numComp]{}; - applyChainRule( NC, - m_dWellElemCompFrac_dCompDens[iwelem], - stack.m_dPhaseFrac[iwelem][0][ip], - dPVF_dC, - Deriv::dC ); - for( integer ic=0; ic( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) { - kernelComponent.computeFlux( iperf, kernelComponent.m_stackVariables ); + kernelComponent.computeFlux( iperf ); } ); } @@ -592,14 +509,14 @@ class PerforationFluxKernel ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_resPhaseVolFrac; ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dResPhaseVolFrac; ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dResCompFrac_dCompDens; - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseDens; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseDens; - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseVisc; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseVisc; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const m_resPhaseCompFrac; - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const m_dResPhaseCompFrac; - ElementViewConst< arrayView3d< real64 const, relperm::USD_RELPERM > > const m_resPhaseRelPerm; - ElementViewConst< arrayView4d< real64 const, relperm::USD_RELPERM_DS > > const m_dResPhaseRelPerm_dPhaseVolFrac; + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_resPhaseDens; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dResPhaseDens; + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_resPhaseVisc; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dResPhaseVisc; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_resPhaseCompFrac; + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const m_dResPhaseCompFrac; + ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const m_resPhaseRelPerm; + ElementViewConst< arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > > const m_dResPhaseRelPerm_dPhaseVolFrac; arrayView1d< real64 const > const m_wellElemGravCoef; arrayView1d< real64 const > const m_wellElemPres; arrayView2d< real64 const, compflow::USD_COMP > const m_wellElemCompDens; @@ -688,6 +605,7 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati //using AbstractBase::m_dPhaseVolFrac; using Base::m_resPhaseCompFrac; using Base::m_dResCompFrac_dCompDens; + using Base::m_dWellElemCompFrac_dCompDens; //using AbstractBase::m_dPhaseCompFrac; //using AbstractBase::m_dCompFrac_dCompDens; /// Compile time value for the number of components @@ -742,61 +660,119 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati multiFluidAccessors, relPermAccessors, disableReservoirToWellFlow ), - m_stack( perforationData, - fluid, - thermalCompFlowAccessors, - thermalMultiFluidAccessors ) + m_wellElemPhaseFrac( fluid.phaseFraction() ), + m_dPhaseFrac( fluid.dPhaseFraction() ), + m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), + m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), + m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), + m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()), + m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables( PerforationData * const perforationData, - MultiFluidBase const & fluid, - ThermalCompFlowAccessors const & thermalCompFlowAccessors, - ThermalMultiFluidAccessors const & thermalMultiFluidAccessors ) - : Base::StackVariables(), - m_wellElemPhaseFrac( fluid.phaseFraction() ), - m_dPhaseFrac( fluid.dPhaseFraction() ), - m_wellElemPhaseEnthalpy( fluid.phaseEnthalpy()), - m_dWellElemPhaseEnthalpy( fluid.dPhaseEnthalpy()), - m_energyPerfFlux( perforationData->getField< fields::well::energyPerforationFlux >()), - m_dEnergyPerfFlux( perforationData->getField< fields::well::dEnergyPerforationFlux >()), - m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), - m_resPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), - m_dResPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ) - {} - - /// Views on well element properties - /// Element phase fraction - arrayView3d< real64 const, multifluid::USD_PHASE > const m_wellElemPhaseFrac; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFrac; - arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; - - /// Views on energy flux - arrayView1d< real64 > const & m_energyPerfFlux; - arrayView3d< real64 > const & m_dEnergyPerfFlux; - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on phase enthalpies - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseEnthalpy; - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseEnthalpy; - }; - template< typename FUNC = NoOpFunc > GEOS_HOST_DEVICE inline void computeFlux( localIndex const iperf ) const { - Base::computeFlux( iperf, m_stack ); + using Deriv = constitutive::multifluid::DerivativeOffset; + using CP_Deriv =constitutive::multifluid::DerivativeOffsetC< NC, IS_THERMAL >; + // initialize outputs + m_energyPerfFlux[iperf]=0; + for( integer ke = 0; ke < 2; ++ke ) + { + for( integer i = 0; i < CP_Deriv::nDer; ++i ) + { + m_dEnergyPerfFlux[iperf][ke][i]=0; + } + } + + Base::computeFlux ( iperf, [&]( localIndex const iwelem, localIndex const er, localIndex const esr, localIndex const ei, localIndex const ip, + real64 const potDiff, real64 const flux, real64 const (&dFlux)[2][CP_Deriv::nDer] ) + { + if( potDiff >= 0 ) // ** reservoir cell is upstream ** + { + + real64 const res_enthalpy = m_resPhaseEnthalpy[er][esr][ei][0][ip]; + + m_energyPerfFlux[iperf] += flux * res_enthalpy; + + // energy equation derivatives WRT res P & T + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * res_enthalpy + + flux * m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * res_enthalpy + + flux * m_dResPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; + // energy equation derivatives WRT well P + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * res_enthalpy; + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * res_enthalpy; + + + // energy equation derivatives WRT reservoir dens + real64 dProp_dC[numComp]{}; + applyChainRule( NC, + m_dResCompFrac_dCompDens[er][esr][ei], + m_dResPhaseEnthalpy[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + + for( integer jc = 0; jc < NC; ++jc ) + { + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dC+jc] += flux * dProp_dC[jc]; + } + } + else // ** reservoir cell is downstream + { + for( integer iphase = 0; iphase < NP; ++iphase ) + { + bool const phaseExists = m_wellElemPhaseFrac[iwelem][0][iphase] > 0.0; + if( !phaseExists ) + continue; + double pflux = m_wellElemPhaseFrac[iwelem][0][iphase]*flux; + real64 const wellelem_enthalpy = m_wellElemPhaseEnthalpy[iwelem][0][iphase]; + m_energyPerfFlux[iperf] += pflux * wellelem_enthalpy; + + // energy equation derivatives WRT res P & T + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dP] += dFlux[TAG::RES][CP_Deriv::dP] * wellelem_enthalpy; + m_dEnergyPerfFlux[iperf][TAG::RES][CP_Deriv::dT] += dFlux[TAG::RES][CP_Deriv::dT] * wellelem_enthalpy; + + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dP] += dFlux[TAG::WELL][CP_Deriv::dP] * wellelem_enthalpy + + pflux * m_dWellElemPhaseEnthalpy[iwelem][0][iphase][Deriv::dP] + + pflux * wellelem_enthalpy * m_dPhaseFrac[iwelem][0][iphase][Deriv::dP]; + m_dEnergyPerfFlux[iperf][TAG::WELL][CP_Deriv::dT] += dFlux[TAG::WELL][CP_Deriv::dT] * wellelem_enthalpy + + pflux * m_dWellElemPhaseEnthalpy[iwelem][0][iphase][Deriv::dT] + + pflux * wellelem_enthalpy * m_dPhaseFrac[iwelem][0][iphase][Deriv::dT]; + + //energy e + real64 dPVF_dC[numComp]{}; + applyChainRule( NC, + m_dWellElemCompFrac_dCompDens[iwelem], + m_dPhaseFrac[iwelem][0][iphase], + dPVF_dC, + Deriv::dC ); + for( integer ic=0; ic static void @@ -816,7 +793,6 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati GEOS_MARK_FUNCTION; forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const iperf ) { - //kernelComponent.setupStack(iperf); kernelComponent.computeFlux( iperf ); } ); @@ -824,8 +800,23 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati protected: - /// Stack continaining thermal variables - StackVariables m_stack; + /// Views on well element properties + /// Element phase fraction + arrayView3d< real64 const, multifluid::USD_PHASE > const m_wellElemPhaseFrac; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFrac; + arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; + + /// Views on energy flux + arrayView1d< real64 > const & m_energyPerfFlux; + arrayView3d< real64 > const & m_dEnergyPerfFlux; + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on phase enthalpies + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const m_resPhaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const m_dResPhaseEnthalpy; }; @@ -883,7 +874,7 @@ class PerforationFluxKernelFactory } }; -} // end namespace thermalPerforationFluxKernels +} // end namespace thermalPerforationFluxKernels } // end namespace geos From 47eada8481681ee011851cb5e85b76b6fc9ca98f Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Mon, 5 Aug 2024 08:15:46 -0700 Subject: [PATCH 54/71] remove tjb specifics --- host-configs/apple/macOS_base.cmake | 30 +++++++---------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/host-configs/apple/macOS_base.cmake b/host-configs/apple/macOS_base.cmake index 08933ec2822..e300aca41a7 100644 --- a/host-configs/apple/macOS_base.cmake +++ b/host-configs/apple/macOS_base.cmake @@ -6,19 +6,12 @@ message("CONFIG_NAME = ${CONFIG_NAME}") set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE PATH "") set(CMAKE_CXX_COMPILER "/usr/bin/clang++" CACHE PATH "") -set(CMAKE_FORTRAN_COMPILER "/usr/bin/gfortra`" CACHE PATH "") set(ENABLE_FORTRAN OFF CACHE BOOL "" FORCE) set(ENABLE_MPI ON CACHE PATH "") -#set(MPI_C_COMPILER "${HOMEBREW_DIR}/bin/mpicc" CACHE PATH "") -#set(MPI_CXX_COMPILER "${HOMEBREW_DIR}/bin/mpicxx" CACHE PATH "") -#set(MPI_Fortran_COMPILER "${HOMEBREW_DIR}/bin/mpifort" CACHE PATH "") -#set(MPIEXEC "${HOMEBREW_DIR}/bin/mpirun" CACHE PATH "") - -set(MPI_C_COMPILER "mpicc" CACHE PATH "") -set(MPI_CXX_COMPILER "mpicxx" CACHE PATH "") -set(MPI_Fortran_COMPILER "mpifort" CACHE PATH "") -set(MPIEXEC "mpirun" CACHE PATH "") +set(MPI_C_COMPILER "${HOMEBREW_DIR}/bin/mpicc" CACHE PATH "") +set(MPI_CXX_COMPILER "${HOMEBREW_DIR}/bin/mpicxx" CACHE PATH "") +set(MPIEXEC "${HOMEBREW_DIR}/bin/mpirun" CACHE PATH "") set(ENABLE_GTEST_DEATH_TESTS ON CACHE BOOL "" FORCE) @@ -26,18 +19,11 @@ set(ENABLE_PVTPackage ON CACHE BOOL "" FORCE) set(ENABLE_CUDA "OFF" CACHE PATH "" FORCE) set(ENABLE_OPENMP "OFF" CACHE PATH "" FORCE) -set(ENABLE_CALIPER "OFF" CACHE PATH "" FORCE ) -set(ENABLE_TRILINOS "OFF" CACHE PATH "" FORCE ) -set(ENABLE_PETSC "OFF" CACHE PATH "" FORCE ) -set(ENABLE_SCOTCH "OFF" CACHE PATH "" FORCE ) -#set( BLAS_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/libblas.dylib CACHE PATH "" FORCE ) -#set( LAPACK_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/liblapack.dylib CACHE PATH "" FORCE ) +set(ENABLE_CALIPER "OFF" CACHE PATH "" FORCE ) -#set( BLAS_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/libblas.3.dylib CACHE PATH "" FORCE ) -#set( LAPACK_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/liblapack.3.dylib CACHE PATH "" FORCE ) -set( BLAS_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/libblas.dylib CACHE PATH "" FORCE ) -set( LAPACK_LIBRARIES /Users/byer3/apps/opt/lapack-3.11/liblapack.dylib CACHE PATH "" FORCE ) +set( BLAS_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/libblas.dylib CACHE PATH "" FORCE ) +set( LAPACK_LIBRARIES ${HOMEBREW_DIR}/opt/lapack/lib/liblapack.dylib CACHE PATH "" FORCE ) set(ENABLE_DOXYGEN OFF CACHE BOOL "" FORCE) set(ENABLE_MATHPRESSO OFF CACHE BOOL "" FORCE ) @@ -54,7 +40,5 @@ endif() # ATS set(ATS_ARGUMENTS "--machine openmpi --ats openmpi_mpirun=${MPIEXEC}" CACHE PATH "") -#set(GEOSX_TPL_DIR "/Users/byer3/GEOS-DEV/thirdPartyLibs/install-mac-debug" CACHE PATH "" FORCE) -set(GEOSX_TPL_DIR "/Users/byer3/GEOS-DEV-20240517/thirdPartyLibs/install-mac_rel-release" CACHE PATH "" FORCE) -set(GEOSX_TPL_DIR "/Users/byer3/gd_20240517/thirdPartyLibs/install-mac_rel-release" CACHE PATH "" FORCE) + include(${CMAKE_CURRENT_LIST_DIR}/../tpls.cmake) From 3a704718f6acb589fb71042bd2609fb5dd755ce9 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Fri, 9 Aug 2024 06:11:58 -0700 Subject: [PATCH 55/71] Fixes for unittests when GPU enabled --- .../fluidFlowTests/testCompFlowUtils.hpp | 14 ++++++++++++++ ...ReservoirCompositionalMultiphaseMSWells.cpp | 18 +++++++----------- ...ReservoirCompositionalMultiphaseSSWells.cpp | 10 +++------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp index 1cb32b3a79b..356ea9e8d4a 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp @@ -53,6 +53,20 @@ void fillNumericalJacobian( arrayView1d< real64 const > const & residual, } ); } +inline +void setNumericalJacobianValue( localIndex const rowIndex, + globalIndex const colIndex, + real64 const val, + CRSMatrixView< real64, globalIndex > const & jacobian ) +{ + forAll< parallelDevicePolicy<> >( 1, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + GEOS_UNUSED_VAR( k ); + jacobian.removeNonZero( rowIndex, colIndex ); + jacobian.insertNonZero( rowIndex, colIndex, val ); + } ); +} + inline void setupProblemFromXML( ProblemManager & problemManager, char const * const xmlInput ) { diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 6ee690fda82..5d09c0a2e97 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -615,25 +615,21 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio if( iwelem == 1 ) { real64 dRdX = 0.0; - globalIndex rowIndex = wellElemDofNumber[0] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + localIndex rowIndex = wellElemDofNumber[0] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; for( integer ider=0; ider< 3; ider++ ) { globalIndex colIndex = wellElemDofNumber[0]+ ider; - jacobianFD.removeNonZero ( rowIndex, colIndex ); - jacobianFD.insertNonZero( rowIndex, colIndex, dRdX ); + setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toView() ); } - jacobianFD.removeNonZero ( rowIndex, wellElemDofNumber[1]+3 ); - jacobianFD.insertNonZero( rowIndex, wellElemDofNumber[1]+3, dRdX ); + globalIndex colIndex = wellElemDofNumber[1]+3; + setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toView() ); } } else { - real64 dRdX = 0.0; - globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; - dRdX = 1.0; - jacobianFD.removeNonZero( rowIndex, rowIndex ); - jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); - //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); + localIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + globalIndex colIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toView() ); } } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp index c3a78fc9b73..4a3e6015b43 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -617,14 +617,10 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio } else { - real64 dRdX = 0.0; - globalIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; - dRdX = 1.0; - jacobianFD.removeNonZero( rowIndex, rowIndex ); - jacobianFD.insertNonZero( rowIndex, rowIndex, dRdX ); - //jacobianFD.addToRow< parallelDeviceAtomic >( rowIndex, &rowIndex, &dRdX, 1 ); + localIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + globalIndex colIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; + setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toView() ); } - } } From 5b66e3413957e038b1c5115ea3ef686de9b6b774 Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Fri, 9 Aug 2024 11:52:27 -0700 Subject: [PATCH 56/71] fix merge error --- src/coreComponents/common/KernelLaunchSelectors.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreComponents/common/KernelLaunchSelectors.hpp b/src/coreComponents/common/KernelLaunchSelectors.hpp index bc0a9bf2105..16ccd91e0a8 100644 --- a/src/coreComponents/common/KernelLaunchSelectors.hpp +++ b/src/coreComponents/common/KernelLaunchSelectors.hpp @@ -19,8 +19,6 @@ #ifndef GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP #define GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP -#include "common/Logger.hpp" - namespace geos { namespace internal From 127d4cfeffef17196b2f79c51c4e02830f428547 Mon Sep 17 00:00:00 2001 From: Matteo Cusini Date: Fri, 9 Aug 2024 21:10:32 -0700 Subject: [PATCH 57/71] test add instead of remove plus insert. --- src/coreComponents/LvArray | 2 +- .../unitTests/fluidFlowTests/testCompFlowUtils.hpp | 7 ++++--- .../testThermalReservoirCompositionalMultiphaseMSWells.cpp | 6 +++--- .../testThermalReservoirCompositionalMultiphaseSSWells.cpp | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/coreComponents/LvArray b/src/coreComponents/LvArray index e7bf1096d57..02ce362c009 160000 --- a/src/coreComponents/LvArray +++ b/src/coreComponents/LvArray @@ -1 +1 @@ -Subproject commit e7bf1096d57558be720f177141c40e4ab69b3f5e +Subproject commit 02ce362c009f11ddb2ade0286df23408d7334c4f diff --git a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp index d2956489be2..e7bc4d6bdfc 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp @@ -57,13 +57,14 @@ inline void setNumericalJacobianValue( localIndex const rowIndex, globalIndex const colIndex, real64 const val, - CRSMatrixView< real64, globalIndex > const & jacobian ) + CRSMatrixView< real64, const globalIndex > const jacobian ) { forAll< parallelDevicePolicy<> >( 1, [=] GEOS_HOST_DEVICE ( localIndex const k ) { GEOS_UNUSED_VAR( k ); - jacobian.removeNonZero( rowIndex, colIndex ); - jacobian.insertNonZero( rowIndex, colIndex, val ); + jacobian.addToRow< parallelDeviceAtomic >( row, &colIndex, &val, 1 ); + // jacobian.removeNonZero( rowIndex, colIndex ); + // jacobian.insertNonZero( rowIndex, colIndex, val ); } ); } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp index 5d09c0a2e97..3e6114d9c18 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp @@ -619,17 +619,17 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio for( integer ider=0; ider< 3; ider++ ) { globalIndex colIndex = wellElemDofNumber[0]+ ider; - setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toView() ); + setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toViewConstSizes() ); } globalIndex colIndex = wellElemDofNumber[1]+3; - setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toView() ); + setNumericalJacobianValue( rowIndex, colIndex, dRdX, jacobianFD.toViewConstSizes() ); } } else { localIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; globalIndex colIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; - setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toView() ); + setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toViewConstSizes() ); } } diff --git a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp index 4a3e6015b43..47c0503a29c 100644 --- a/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp +++ b/src/coreComponents/unitTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp @@ -619,7 +619,7 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio { localIndex rowIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; globalIndex colIndex = wellElemDofNumber[iwelem] + compositionalMultiphaseWellKernels::ColOffset::DCOMP + NC+1;; - setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toView() ); + setNumericalJacobianValue( rowIndex, colIndex, 1.0, jacobianFD.toViewConstSizes() ); } } } From b711a877f8d02c70bfaa379c78f1b95e603db676 Mon Sep 17 00:00:00 2001 From: Matteo Cusini <49037133+CusiniM@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:26:03 -0700 Subject: [PATCH 58/71] Remove & and add const. --- .../fluidFlow/wells/PerforationFluxKernels.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index db71efee6bd..cca04dfe997 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -804,12 +804,12 @@ class PerforationFluxKernel : public isothermalPerforationFluxKernels::Perforati /// Element phase fraction arrayView3d< real64 const, multifluid::USD_PHASE > const m_wellElemPhaseFrac; arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dPhaseFrac; - arrayView3d< real64 const, multifluid::USD_PHASE > m_wellElemPhaseEnthalpy; - arrayView4d< real64 const, multifluid::USD_PHASE_DC > m_dWellElemPhaseEnthalpy; + arrayView3d< real64 const, multifluid::USD_PHASE > const m_wellElemPhaseEnthalpy; + arrayView4d< real64 const, multifluid::USD_PHASE_DC > const m_dWellElemPhaseEnthalpy; /// Views on energy flux - arrayView1d< real64 > const & m_energyPerfFlux; - arrayView3d< real64 > const & m_dEnergyPerfFlux; + arrayView1d< real64 > const m_energyPerfFlux; + arrayView3d< real64 > const m_dEnergyPerfFlux; /// Views on temperature ElementViewConst< arrayView1d< real64 const > > const m_temp; From 17cc02354719a520b4c0a6fe9f77a972d5584b4c Mon Sep 17 00:00:00 2001 From: Matteo Cusini <49037133+CusiniM@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:39:16 -0700 Subject: [PATCH 59/71] Update src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp --- .../unitTests/fluidFlowTests/testCompFlowUtils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp index e7bc4d6bdfc..7db32d9c752 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp @@ -62,7 +62,7 @@ void setNumericalJacobianValue( localIndex const rowIndex, forAll< parallelDevicePolicy<> >( 1, [=] GEOS_HOST_DEVICE ( localIndex const k ) { GEOS_UNUSED_VAR( k ); - jacobian.addToRow< parallelDeviceAtomic >( row, &colIndex, &val, 1 ); + jacobian.addToRow< parallelDeviceAtomic >( rowIndex, &colIndex, &val, 1 ); // jacobian.removeNonZero( rowIndex, colIndex ); // jacobian.insertNonZero( rowIndex, colIndex, val ); } ); From 720901cbeaced6e154a9875fa6fd88f1c36f202b Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Mon, 12 Aug 2024 08:54:02 -0700 Subject: [PATCH 60/71] 1) dont allocate temperature_n for isothermal run, 2) uncrustify style --- .../fluidFlow/wells/WellSolverBase.cpp | 5 ++- .../docs/CompositionalMultiphaseWell.rst | 4 +- .../docs/wellElementSubRegion_other.rst | 39 ++++++++++--------- src/coreComponents/schema/schema.xsd.other | 2 + 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 4f80b3f76cb..14bd1fcab70 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -122,7 +122,10 @@ void WellSolverBase::registerDataOnMesh( Group & meshBodies ) subRegion.registerField< fields::well::pressure_n >( getName() ); subRegion.registerField< fields::well::temperature >( getName() ); - subRegion.registerField< fields::well::temperature_n >( getName() ); + if( isThermal() ) + { + subRegion.registerField< fields::well::temperature_n >( getName() ); + } subRegion.registerField< fields::well::gravityCoefficient >( getName() ); diff --git a/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst b/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst index 156fac4e1b5..a88b696ae6c 100644 --- a/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst +++ b/src/coreComponents/schema/docs/CompositionalMultiphaseWell.rst @@ -6,13 +6,13 @@ Name Type Default Description allowLocalCompDensityChopping integer 1 Flag indicating whether local (cell-wise) chopping of negative compositions is allowed cflFactor real64 0.5 Factor to apply to the `CFL condition `_ when calculating the maximum allowable time step. Values should be in the interval (0,1] initialDt real64 1e+99 Initial time-step value required by the solver to the event manager. -isThermal integer 0 Flag indicating whether the problem is thermal or not. +isThermal integer 0 Flag indicating whether the problem is thermal or not. logLevel integer 0 Log level maxAbsolutePressureChange real64 -1 Maximum (absolute) pressure change in a Newton iteration maxCompFractionChange real64 1 Maximum (absolute) change in a component fraction between two Newton iterations maxRelativeCompDensChange real64 1.79769e+308 Maximum (relative) change in a component density between two Newton iterations maxRelativePressureChange real64 1 Maximum (relative) change in pressure between two Newton iterations (recommended with rate control) -maxRelativeTemperatureChange real64 1 Maximum (relative) change in temperature between two Newton iterations +maxRelativeTemperatureChange real64 1 Maximum (relative) change in temperature between two Newton iterations name groupName required A name is required for any non-unique nodes targetRegions groupNameRef_array required Allowable regions that the solver may be applied to. Note that this does not indicate that the solver will be applied to these regions, only that allocation will occur such that the solver may be applied to these regions. The decision about what regions this solver will beapplied to rests in the EventManager. useMass integer 0 Use mass formulation instead of molar diff --git a/src/coreComponents/schema/docs/wellElementSubRegion_other.rst b/src/coreComponents/schema/docs/wellElementSubRegion_other.rst index 6ceeee5546c..296c68757cb 100644 --- a/src/coreComponents/schema/docs/wellElementSubRegion_other.rst +++ b/src/coreComponents/schema/docs/wellElementSubRegion_other.rst @@ -1,23 +1,24 @@ -========================= ================================================================= ====================================================================== -Name Type Description -========================= ================================================================= ====================================================================== -domainBoundaryIndicator integer_array (no description available) -ghostRank integer_array (no description available) -globalToLocalMap geos_mapBase > (no description available) -isExternal integer_array (no description available) -localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. -location real64_array2d For each perforation, physical location (x,y,z coordinates) -numPerforationsGlobal globalIndex (no description available) -reservoirElementIndex integer_array For each perforation, element index of the perforated element -reservoirElementRegion integer_array For each perforation, elementRegion index of the perforated element -reservoirElementSubregion integer_array For each perforation, elementSubRegion index of the perforated element -wellElementIndex integer_array For each perforation, index of the well element -wellSkinFactor real64_array For each perforation, well skin factor -wellTransmissibility real64_array For each perforation, well transmissibility -neighborData node :ref:`DATASTRUCTURE_neighborData` -sets node :ref:`DATASTRUCTURE_sets` -========================= ================================================================= ====================================================================== +=========================== ================================================================= ====================================================================== +Name Type Description +=========================== ================================================================= ====================================================================== +domainBoundaryIndicator integer_array (no description available) +ghostRank integer_array (no description available) +globalToLocalMap geos_mapBase > (no description available) +isExternal integer_array (no description available) +localToGlobalMap globalIndex_array Array that contains a map from localIndex to globalIndex. +location real64_array2d For each perforation, physical location (x,y,z coordinates) +numPerforationsGlobal globalIndex (no description available) +reservoirElementGlobalIndex globalIndex_array For each perforation, global element index of the perforated element +reservoirElementIndex integer_array For each perforation, element index of the perforated element +reservoirElementRegion integer_array For each perforation, elementRegion index of the perforated element +reservoirElementSubregion integer_array For each perforation, elementSubRegion index of the perforated element +wellElementIndex integer_array For each perforation, index of the well element +wellSkinFactor real64_array For each perforation, well skin factor +wellTransmissibility real64_array For each perforation, well transmissibility +neighborData node :ref:`DATASTRUCTURE_neighborData` +sets node :ref:`DATASTRUCTURE_sets` +=========================== ================================================================= ====================================================================== diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other index fac7e939187..25e0ae8903d 100644 --- a/src/coreComponents/schema/schema.xsd.other +++ b/src/coreComponents/schema/schema.xsd.other @@ -3245,6 +3245,8 @@ + + From fdeea3a766376292b9a38908bc00603bd084e9bd Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 20 Aug 2024 06:22:05 -0700 Subject: [PATCH 61/71] remove debug std::cout --- src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp index 9fad9bcfb4d..d2a03d3c0f7 100644 --- a/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp +++ b/src/coreComponents/finiteVolume/TwoPointFluxApproximation.cpp @@ -130,7 +130,6 @@ void TwoPointFluxApproximation::computeCellStencil( MeshLevel & mesh ) const localIndex const ei, CellElementRegion const & ) { - std::cout << "computeCellStencil " << ei << std::endl; regionFilter.insert( ei ); } ); From 4cf2106427721a93d0c02ff93c5cae5effb8960b Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Thu, 5 Sep 2024 09:51:16 -0700 Subject: [PATCH 62/71] remove std::cout --- .../physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp index 6febb9ff0f1..f9901f30490 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp @@ -13,6 +13,8 @@ * ------------------------------------------------------------------------------------------------------------ */ + + /** * @file CompositionalMultiphaseFVM.cpp */ From 35cf15b7fbbef38a933d066a8d5437ae33e94ae1 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:56:27 -0700 Subject: [PATCH 63/71] code cleanup --- .gitmodules | 5 ++--- src/coreComponents/common/KernelLaunchSelectors.hpp | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index 0ce1e5d5084..029ba71a9ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,6 +11,5 @@ path = src/coreComponents/fileIO/coupling/hdf5_interface url = ../../GEOS-DEV/hdf5_interface.git [submodule "scripts/uberenv"] - path = scripts/uberenv - url = ../../LLNL/uberenv.git - + path = scripts/uberenv + url = ../../LLNL/uberenv.git diff --git a/src/coreComponents/common/KernelLaunchSelectors.hpp b/src/coreComponents/common/KernelLaunchSelectors.hpp index 16ccd91e0a8..8ebec2fed98 100644 --- a/src/coreComponents/common/KernelLaunchSelectors.hpp +++ b/src/coreComponents/common/KernelLaunchSelectors.hpp @@ -46,7 +46,6 @@ void kernelLaunchSelectorCompThermSwitch( T value, bool const isThermal, LAMBDA { static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); - //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); if( isThermal ) { switch( value ) @@ -95,7 +94,6 @@ void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) { static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); - //constexpr T a = isThermal ? std::integral_constant< T, 1 >() : std::integral_constant< T, 0 >(); if( n_phase == 1 ) { switch( value ) From f1f633bc37f94b2afafa4941e4e1649346548b38 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:31:40 -0700 Subject: [PATCH 64/71] Code cleanup --- .../common/KernelLaunchSelectors.hpp | 201 +++++++++--------- src/coreComponents/dataRepository/Group.hpp | 2 +- ...malCompositionalMultiphaseReservoirFVM.hpp | 25 ++- .../fluidFlow/CompositionalMultiphaseBase.cpp | 1 - .../wells/CompositionalMultiphaseWell.cpp | 3 - .../CompositionalMultiphaseWellFields.hpp | 16 -- 6 files changed, 122 insertions(+), 126 deletions(-) diff --git a/src/coreComponents/common/KernelLaunchSelectors.hpp b/src/coreComponents/common/KernelLaunchSelectors.hpp index 8ebec2fed98..f6040f788ea 100644 --- a/src/coreComponents/common/KernelLaunchSelectors.hpp +++ b/src/coreComponents/common/KernelLaunchSelectors.hpp @@ -24,6 +24,49 @@ namespace geos namespace internal { +template< typename S, typename T, typename LAMBDA > +void invokePhaseDispatchLambda ( S val, T numPhases, LAMBDA && lambda ) +{ + if( numPhases == 1 ) + { + lambda( val, std::integral_constant< T, 1 >()); + return; + } + else if( numPhases == 2 ) + { + lambda( val, std::integral_constant< T, 2 >()); + return; + } + else if( numPhases == 3 ) + { + lambda( val, std::integral_constant< T, 3 >()); + return; + } + else + { + GEOS_ERROR( "Unsupported state: " << numPhases ); + } +}; + +template< typename S, typename T, typename LAMBDA > +void invokeThermalDispatchLambda ( S val, T isThermal, LAMBDA && lambda ) +{ + if( isThermal == 1 ) + { + lambda( val, std::integral_constant< T, 1 >()); + return; + } + else if( isThermal == 0 ) + { + lambda( val, std::integral_constant< T, 0 >()); + return; + } + else + { + GEOS_ERROR( "Unsupported state: " << isThermal ); + } +}; + template< typename T, typename LAMBDA > void kernelLaunchSelectorThermalSwitch( T value, LAMBDA && lambda ) { @@ -32,12 +75,19 @@ void kernelLaunchSelectorThermalSwitch( T value, LAMBDA && lambda ) switch( value ) { case 0: - { lambda( std::integral_constant< T, 0 >() ); return; } + { + lambda( std::integral_constant< T, 0 >() ); + return; + } case 1: - { lambda( std::integral_constant< T, 1 >() ); return; } - + { + lambda( std::integral_constant< T, 1 >() ); + return; + } default: - { GEOS_ERROR( "Unsupported thermal state: " << value ); } + { + GEOS_ERROR( "Unsupported thermal state: " << value ); + } } } @@ -46,120 +96,77 @@ void kernelLaunchSelectorCompThermSwitch( T value, bool const isThermal, LAMBDA { static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); - if( isThermal ) + + switch( value ) { - switch( value ) + case 1: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 1 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 1 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 1 >()); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + invokeThermalDispatchLambda( std::integral_constant< T, 1 >(), isThermal, lambda ); return; } - } - else - { - switch( value ) + case 2: + { + invokeThermalDispatchLambda( std::integral_constant< T, 2 >(), isThermal, lambda ); + return; + } + case 3: + { + invokeThermalDispatchLambda( std::integral_constant< T, 3 >(), isThermal, lambda ); + return; + } + case 4: + { + invokeThermalDispatchLambda( std::integral_constant< T, 4 >(), isThermal, lambda ); + return; + } + case 5: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 0 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 0 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 0 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 0 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 0 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + invokeThermalDispatchLambda( std::integral_constant< T, 5 >(), isThermal, lambda ); + return; + } + default: + { + GEOS_ERROR( "Unsupported number of components: " << value ); } } } - template< typename T, typename LAMBDA > void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) { static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: value type should be integral" ); - - if( n_phase == 1 ) + switch( value ) { - switch( value ) + case 1: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 1 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 1 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 1 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 1 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 1 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + invokePhaseDispatchLambda( std::integral_constant< T, 1 >(), n_phase, lambda ); + return; } - } - else if( n_phase == 2 ) - { - switch( value ) + case 2: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 2 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 2 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 2 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 2 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 2 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + invokePhaseDispatchLambda( std::integral_constant< T, 2 >(), n_phase, lambda ); + return; } - - } - else if( n_phase == 3 ) - { - switch( value ) + case 3: { - case 1: - { - lambda( std::integral_constant< T, 1 >(), std::integral_constant< T, 3 >() ); return; - } - case 2: - { lambda( std::integral_constant< T, 2 >(), std::integral_constant< T, 3 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >(), std::integral_constant< T, 3 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >(), std::integral_constant< T, 3 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >(), std::integral_constant< T, 3 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } + invokePhaseDispatchLambda( std::integral_constant< T, 3 >(), n_phase, lambda ); + return; } - } - else - { - { GEOS_ERROR( "Unsupported number of phases: " << n_phase ); } + case 4: + { + invokePhaseDispatchLambda( std::integral_constant< T, 4 >(), n_phase, lambda ); + return; + } + case 5: + { + invokePhaseDispatchLambda( std::integral_constant< T, 5 >(), n_phase, lambda ); + return; + } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } } } + + } // end namspace internal } // end namespace geos diff --git a/src/coreComponents/dataRepository/Group.hpp b/src/coreComponents/dataRepository/Group.hpp index d6e41a83d99..44dbd6bb0d4 100644 --- a/src/coreComponents/dataRepository/Group.hpp +++ b/src/coreComponents/dataRepository/Group.hpp @@ -30,7 +30,6 @@ #include -#include #ifndef NOCHARTOSTRING_KEYLOOKUP /// macro definition to enable/disable char * lookups @@ -880,6 +879,7 @@ class Group for( auto const & subGroupIter : m_subGroups ) { + std::cout << indent << subGroupIter.second->getName() << std::endl; subGroupIter.second->generateDataStructureSkeleton( level + 1 ); } } diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp index b9433861988..81702aa2f8b 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/ThermalCompositionalMultiphaseReservoirFVM.hpp @@ -34,18 +34,27 @@ namespace mgr * @brief ThermalCompositionalMultiphaseReservoirFVM strategy. * * Labels description stored in point_marker_array - * 0 = pressure - * 1 = density - * ... = densities - * numLabels - 2 = last density - * numLabels - 1 = temperature + * 0 = reservoir pressure + * 1 = reservoir density (component 1 ) + * ... = reservoir densities (# components , NC) + * NC + 1 = reservoir temperature * - * 2-level MGR reduction strategy - * - 1st level: eliminate the reservoir density associated with the volume constraint - * - 2nd level: eliminate the other reservoir densities + * numResLabels - 1 = reservoir temperature + * numResLabels = well pressure + * numResLabels + 1 = well density + * ... = ... (well densities) + * numResLabels + numWellLabels - 3 = last well density + * numResLabels + numWellLabels - 2 = well rate + * numResLabels + numWellLabels - 1 = well temperature + * + * 3-level MGR reduction strategy + * - 1st level: eliminate the well block + * - 2nd level: eliminate the reservoir density associated with the volume constraint + * - 3rd level: eliminate the remaining the reservoir densities * - The coarse grid (pressure and temperature system) is solved with BoomerAMG with numFunctions==2. * */ + class ThermalCompositionalMultiphaseReservoirFVM : public MGRStrategyBase< 3 > { public: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index 95d3adbd3a6..afed3fbe9fe 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp @@ -2268,7 +2268,6 @@ void CompositionalMultiphaseBase::computeCFLNumbers( geos::DomainPartition & dom fluxApprox.forAllStencils( mesh, [&] ( auto & stencil ) { typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); - std::cout << "fluxApprox.forAllStencils : mesh " << mesh.getName() << std::endl; // While this kernel is waiting for a factory class, pass all the accessors here isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1 diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 5372455dbe4..d7ca4afda62 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -593,7 +593,6 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL ) { - //integer constexpr NUM_COMP = NC(); integer constexpr IS_THERMAL = ISTHERMAL(); GEOS_UNUSED_VAR( NC ); // bring everything back to host, capture the scalars by reference @@ -1914,8 +1913,6 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time bool controlHasSwitched = false; isothermalCompositionalMultiphaseBaseKernels:: KernelLaunchSelectorCompTherm< PressureRelationKernel >( numFluidComponents(), isThermal, - //isothermalCompositionalMultiphaseBaseKernels::KernelLaunchSelector1< - // PressureRelationKernel >( numFluidComponents(), subRegion.size(), dofManager.rankOffset(), subRegion.isLocallyOwned(), diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp index 1bafc1a396e..9a3b649bbbc 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp @@ -113,23 +113,7 @@ DECLARE_FIELD( phaseVolumeFraction_n, NOPLOT, WRITE_AND_READ, "Phase volume fraction at the previous converged time step" ); -/* - DECLARE_FIELD( dCurrentBHP, - "dCurrentBHP", - array1d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of current BHP with respect to pressure, temperature, and global component density" ); - DECLARE_FIELD( dCurrentPhaseVolRate, - "dCurrentPhaseVolRate", - array2dLayoutPhase, - 0, - NOPLOT, - NO_WRITE, - "Derivative of current phase volume rate with respect to pressure, temperature, and global component density" ); - */ DECLARE_FIELD( totalMassDensity, "totalMassDensity", array1d< real64 >, From e659c7c233322e3cb30c014a638c88679594512b Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:34:21 -0700 Subject: [PATCH 65/71] move KernalLaunchSelectors from common to physicsSolvers --- .../{common => physicsSolvers}/KernelLaunchSelectors.hpp | 6 +++--- .../IsothermalCompositionalMultiphaseBaseKernels.hpp | 2 +- .../fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp | 2 +- .../fluidFlow/wells/PerforationFluxKernels.hpp | 4 +--- .../multiphysics/SinglePhaseReservoirAndWells.cpp | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) rename src/coreComponents/{common => physicsSolvers}/KernelLaunchSelectors.hpp (96%) diff --git a/src/coreComponents/common/KernelLaunchSelectors.hpp b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp similarity index 96% rename from src/coreComponents/common/KernelLaunchSelectors.hpp rename to src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp index f6040f788ea..e64ff9d638d 100644 --- a/src/coreComponents/common/KernelLaunchSelectors.hpp +++ b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp @@ -16,8 +16,8 @@ * @file KernelLaunchSelectors.hpp */ -#ifndef GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP -#define GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP +#ifndef GEOS_PHYSICSSOLVERS_KERNELLAUNCHSELECTORS_HPP +#define GEOS_PHYSICSSOLVERS_KERNELLAUNCHSELECTORS_HPP namespace geos { @@ -171,4 +171,4 @@ void kernelLaunchSelectorCompPhaseSwitch( T value, T n_phase, LAMBDA && lambda ) } // end namespace geos -#endif // GEOS_COMMON_KERNELLAUNCHSELECTORS_HPP +#endif // GEOS_PHYSICSSOLVERS_KERNELLAUNCHSELECTORS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp index 3f7c9d86055..7836591b72d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp @@ -24,7 +24,6 @@ #include "common/DataLayouts.hpp" #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" -#include "common/KernelLaunchSelectors.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "functions/TableFunction.hpp" @@ -35,6 +34,7 @@ #include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" #include "physicsSolvers/SolverBaseKernels.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" +#include "physicsSolvers/KernelLaunchSelectors.hpp" namespace geos { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp index 29169c13145..ce48868edea 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellKernels.hpp @@ -23,13 +23,13 @@ #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" -#include "common/KernelLaunchSelectors.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidFields.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" #include "mesh/ElementRegionManager.hpp" #include "mesh/ObjectManagerBase.hpp" +#include "physicsSolvers/KernelLaunchSelectors.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp index cca04dfe997..6c042f18d34 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/PerforationFluxKernels.hpp @@ -22,19 +22,17 @@ #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" -#include "common/KernelLaunchSelectors.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidFields.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" #include "mesh/ElementRegionManager.hpp" #include "mesh/ObjectManagerBase.hpp" +#include "physicsSolvers/KernelLaunchSelectors.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -//#include "physicsSolvers/fluidFlow/IsothermalCompositionalMultiphaseBaseKernels.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" -//#include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellTags.hpp" #include "physicsSolvers/fluidFlow/wells/WellFields.hpp" diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp index 282cfba24c1..4a56172c477 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhaseReservoirAndWells.cpp @@ -21,8 +21,8 @@ #include "SinglePhaseReservoirAndWells.hpp" #include "common/TimingMacros.hpp" -#include "common/KernelLaunchSelectors.hpp" #include "mesh/PerforationFields.hpp" +#include "physicsSolvers/KernelLaunchSelectors.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseFVM.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellKernels.hpp" From 316226699df4135c6be9135e5f35d822b16985b6 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:11:51 -0700 Subject: [PATCH 66/71] PR requested changes --- src/coreComponents/mesh/WellElementSubRegion.cpp | 2 ++ .../multiphysics/CoupledReservoirAndWellKernels.hpp | 2 +- .../unitTests/fluidFlowTests/testCompFlowUtils.hpp | 2 -- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index 1bdd3423ac6..f47d6689922 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -148,6 +148,7 @@ void collectElementNodes( CellElementSubRegion const & subRegion, * @param[inout] erMatched the region index of the reservoir element that contains "location", if any * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any + * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any */ bool visitNeighborElements( MeshLevel const & mesh, real64 const (&location)[3], @@ -294,6 +295,7 @@ void initializeLocalSearch( MeshLevel const & mesh, * @param[inout] erMatched the region index of the reservoir element that contains "location", if any * @param[inout] esrMatched the subregion index of the reservoir element that contains "location", if any * @param[inout] eiMatched the element index of the reservoir element that contains "location", if any + * @param[inout] giMatched the element global index of the reservoir element that contains "location", if any */ bool searchLocalElements( MeshLevel const & mesh, real64 const (&location)[3], diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index cd7ef201fdd..91b568e6eab 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -463,7 +463,7 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM localIndex localDofIndexPres = ke * resNumDOF; localPerfJacobian[TAG::RES ][localDofIndexPres] = m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; localPerfJacobian[TAG::WELL ][localDofIndexPres] = -m_dt * m_dEnergyPerfFlux[iperf][ke][CP_Deriv::dP]; - //localDofIndexPres += 1; + // populate local flux vector and derivatives for( integer ic = 0; ic < numComp; ++ic ) { diff --git a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp index 7db32d9c752..eefff08fcd4 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testCompFlowUtils.hpp @@ -63,8 +63,6 @@ void setNumericalJacobianValue( localIndex const rowIndex, { GEOS_UNUSED_VAR( k ); jacobian.addToRow< parallelDeviceAtomic >( rowIndex, &colIndex, &val, 1 ); - // jacobian.removeNonZero( rowIndex, colIndex ); - // jacobian.insertNonZero( rowIndex, colIndex, val ); } ); } From dcb533b64048f1337a6330f710e8e2bde030802a Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Sun, 27 Oct 2024 08:25:48 -0700 Subject: [PATCH 67/71] fix pedantry --- src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp index e64ff9d638d..bf6ced9d6c8 100644 --- a/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp +++ b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp @@ -46,7 +46,7 @@ void invokePhaseDispatchLambda ( S val, T numPhases, LAMBDA && lambda ) { GEOS_ERROR( "Unsupported state: " << numPhases ); } -}; +} template< typename S, typename T, typename LAMBDA > void invokeThermalDispatchLambda ( S val, T isThermal, LAMBDA && lambda ) From 72f8895fcb99569f36854f84eb47256b019d030c Mon Sep 17 00:00:00 2001 From: Matteo Cusini Date: Mon, 28 Oct 2024 08:23:18 -0700 Subject: [PATCH 68/71] fix compilation errors. --- src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp index e64ff9d638d..6a07386bd79 100644 --- a/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp +++ b/src/coreComponents/physicsSolvers/KernelLaunchSelectors.hpp @@ -46,7 +46,7 @@ void invokePhaseDispatchLambda ( S val, T numPhases, LAMBDA && lambda ) { GEOS_ERROR( "Unsupported state: " << numPhases ); } -}; +} template< typename S, typename T, typename LAMBDA > void invokeThermalDispatchLambda ( S val, T isThermal, LAMBDA && lambda ) @@ -65,7 +65,7 @@ void invokeThermalDispatchLambda ( S val, T isThermal, LAMBDA && lambda ) { GEOS_ERROR( "Unsupported state: " << isThermal ); } -}; +} template< typename T, typename LAMBDA > void kernelLaunchSelectorThermalSwitch( T value, LAMBDA && lambda ) From 12e93141ca432e3cd17fcfe189d277a63d784f0a Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Tue, 29 Oct 2024 07:04:48 -0700 Subject: [PATCH 69/71] update baselines --- .integrated_tests.yaml | 2 +- BASELINE_NOTES.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.integrated_tests.yaml b/.integrated_tests.yaml index 2d289765a28..24a926326a6 100644 --- a/.integrated_tests.yaml +++ b/.integrated_tests.yaml @@ -1,6 +1,6 @@ baselines: bucket: geosx - baseline: integratedTests/baseline_integratedTests-pr2878-8188-ed2ded2 + baseline: integratedTests/baseline_integratedTests-pr3156-8300-32d1d28 allow_fail: all: '' diff --git a/BASELINE_NOTES.md b/BASELINE_NOTES.md index 65cd8d82bd9..51b738f22fa 100644 --- a/BASELINE_NOTES.md +++ b/BASELINE_NOTES.md @@ -6,6 +6,10 @@ This file is designed to track changes to the integrated test baselines. Any developer who updates the baseline ID in the .integrated_tests.yaml file is expected to create an entry in this file with the pull request number, date, and their justification for rebaselining. These notes should be in reverse-chronological order, and use the following time format: (YYYY-MM-DD). +PR #3156 (2024-10-29) +==================== +Restart check errors due to 1) schema node added to enable thermal option in well model and 2) arrays removed/added for option. Max difference errors due treatment of shutin wells. Previously non-zero rate value reported for shutin well, new code will set rate arrays to zero. + PR #2878 (2024-10-17) ===================== Sorted region cellBlocks names alphabetically. Therefore affected ordering of: faceManager/elemSubRegionList, nodeManager/elemList, nodeManager/elemSubRegionList, SurfaceElementSubRegion::fractureElementsToCellSubRegions, field::perforation::reservoirElementSubregion. From aa71f2a2c1d660907ff5707fa6b93065413c804e Mon Sep 17 00:00:00 2001 From: Thomas James Byer Date: Wed, 30 Oct 2024 15:10:46 -0700 Subject: [PATCH 70/71] perfs global res cell index set with wrong array (node instead of cell values), quantites only used for reporting --- src/coreComponents/mesh/WellElementSubRegion.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index 7fc4ca3d8e4..daf53c67621 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -166,7 +166,6 @@ bool visitNeighborElements( MeshLevel const & mesh, ArrayOfArraysView< localIndex const > const & toElementRegionList = nodeManager.elementRegionList(); ArrayOfArraysView< localIndex const > const & toElementSubRegionList = nodeManager.elementSubRegionList(); ArrayOfArraysView< localIndex const > const & toElementList = nodeManager.elementList(); - arrayView1d< globalIndex const > localToGlobalIndex = nodeManager.localToGlobalMap(); arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const referencePosition = nodeManager.referencePosition().toViewConst(); @@ -195,7 +194,6 @@ bool visitNeighborElements( MeshLevel const & mesh, localIndex const er = toElementRegionList[currNode][b]; localIndex const esr = toElementSubRegionList[currNode][b]; localIndex const eiLocal = toElementList[currNode][b]; - globalIndex const gIndex = localToGlobalIndex[eiLocal]; CellElementRegion const & region = elemManager.getRegion< CellElementRegion >( er ); CellElementSubRegion const & subRegion = region.getSubRegion< CellElementSubRegion >( esr ); arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList(); @@ -223,7 +221,7 @@ bool visitNeighborElements( MeshLevel const & mesh, erMatched = er; esrMatched = esr; eiMatched = eiLocal; - giMatched = gIndex; + giMatched = eiGlobal; matched = true; break; } From f5ef324cd865e7325172ea42cc48bb0ed603d718 Mon Sep 17 00:00:00 2001 From: Matteo Cusini <49037133+CusiniM@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:54:35 -0700 Subject: [PATCH 71/71] Update .integrated_tests.yaml --- .integrated_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.integrated_tests.yaml b/.integrated_tests.yaml index 24a926326a6..1026f009fb0 100644 --- a/.integrated_tests.yaml +++ b/.integrated_tests.yaml @@ -1,6 +1,6 @@ baselines: bucket: geosx - baseline: integratedTests/baseline_integratedTests-pr3156-8300-32d1d28 + baseline: integratedTests/baseline_integratedTests-pr3156-8366-aa71f2a allow_fail: all: ''