diff --git a/inputFiles/compositionalMultiphaseFlow/issue_3497/flowOnly_staircase_co2_3d_mfd.xml b/inputFiles/compositionalMultiphaseFlow/issue_3497/flowOnly_staircase_co2_3d_mfd.xml new file mode 100644 index 00000000000..4954c251290 --- /dev/null +++ b/inputFiles/compositionalMultiphaseFlow/issue_3497/flowOnly_staircase_co2_3d_mfd.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputFiles/compositionalMultiphaseFlow/issue_3497/flowOnly_staircase_co2_3d_tpfa.xml b/inputFiles/compositionalMultiphaseFlow/issue_3497/flowOnly_staircase_co2_3d_tpfa.xml new file mode 100644 index 00000000000..a7038800200 --- /dev/null +++ b/inputFiles/compositionalMultiphaseFlow/issue_3497/flowOnly_staircase_co2_3d_tpfa.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cmake/GeosxOptions.cmake b/src/cmake/GeosxOptions.cmake index fe3adabcc4b..ebc45c3e929 100644 --- a/src/cmake/GeosxOptions.cmake +++ b/src/cmake/GeosxOptions.cmake @@ -147,7 +147,7 @@ message( "CMAKE_CXX_COMPILER_ID = ${CMAKE_CXX_COMPILER_ID}" ) blt_append_custom_compiler_flag( FLAGS_VAR CMAKE_CXX_FLAGS DEFAULT "${OpenMP_CXX_FLAGS}" ) blt_append_custom_compiler_flag( FLAGS_VAR CMAKE_CXX_FLAGS GNU "-Wpedantic -pedantic-errors -Wshadow -Wfloat-equal -Wcast-align -Wcast-qual" - CLANG "-Wpedantic -pedantic-errors -Wshadow -Wfloat-equal -Wno-cast-align -Wcast-qual" + CLANG "-Wpedantic -pedantic-errors -Wshadow -Wfloat-equal -Wno-cast-align -Wcast-qual -Wno-shorten-64-to-32" ) blt_append_custom_compiler_flag( FLAGS_VAR CMAKE_CXX_FLAGS_DEBUG diff --git a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp index 5f1b8a87f98..7081d021e9e 100644 --- a/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp +++ b/src/coreComponents/linearAlgebra/interfaces/hypre/mgrStrategies/CompositionalMultiphaseHybridFVM.hpp @@ -81,10 +81,12 @@ class CompositionalMultiphaseHybridFVM : public MGRStrategyBase< 3 > // Level 1 m_levelFRelaxType[1] = MGRFRelaxationType::none; - m_levelInterpType[1] = MGRInterpolationType::jacobi; + m_levelFRelaxIters[1] = 1; + m_levelInterpType[1] = MGRInterpolationType::injection; m_levelRestrictType[1] = MGRRestrictionType::blockColLumped; // True-IMPES m_levelCoarseGridMethod[1] = MGRCoarseGridMethod::galerkin; - m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::none; + m_levelGlobalSmootherType[1] = MGRGlobalSmootherType::ilu0; + m_levelGlobalSmootherIters[1] = 1; // Level 2 m_levelFRelaxType[2] = MGRFRelaxationType::jacobi; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp index f4a8d3c3ffd..f661eb86f38 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp @@ -144,7 +144,8 @@ void CompositionalMultiphaseFVM::postInputInitialization() FluxApproximationBase const & fluxApprox = fvManager.getFluxApproximation( m_discretizationName ); auto const & upwindingParams = fluxApprox.upwindingParams(); if( upwindingParams.upwindingScheme == UpwindingScheme::C1PPU || - upwindingParams.upwindingScheme == UpwindingScheme::IHU ) + upwindingParams.upwindingScheme == UpwindingScheme::IHU || + upwindingParams.upwindingScheme == UpwindingScheme::HU2PH ) { GEOS_ERROR( GEOS_FMT( "{}: {} is not available for {}", getDataContext(), @@ -273,7 +274,9 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, kernelFlags.set( KernelFlags::C1PPU ); else if( upwindingParams.upwindingScheme == UpwindingScheme::IHU ) kernelFlags.set( KernelFlags::IHU ); - + else if( upwindingParams.upwindingScheme == UpwindingScheme::HU2PH ) + kernelFlags.set( KernelFlags::HU2PH ); + string const & elemDofKey = dofManager.getKey( viewKeyStruct::elemDofFieldString() ); fluxApprox.forAllStencils( mesh, [&] ( auto & stencil ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp index 7f1998b66a1..229f276f6b5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp @@ -83,8 +83,6 @@ void CompositionalMultiphaseHybridFVM::registerDataOnMesh( Group & meshBodies ) // Register the face data for temperature faceManager.registerField< flow::faceTemperature >( getName() ); - - // Register the bc face data for pressure faceManager.registerField< flow::bcPressure >( getName() ); @@ -106,11 +104,11 @@ void CompositionalMultiphaseHybridFVM::registerDataOnMesh( Group & meshBodies ) reference().resizeDimension< 1, 2 >( m_numPhases, m_numComponents ); // Register boundary face indicator (1 for boundary faces with Dirichlet BCs, 0 for interior) - // Used to skip flux continuity constraints for boundary faces faceManager.registerField< flow::isBoundaryFace >( getName() ); - // auxiliary data for the buoyancy coefficient - faceManager.registerField< flow::mimGravityCoefficient >( getName() ); + // precomputed mimetic gravity-driven trans coefficient on faces + faceManager.registerField< flow::mimeticTransGgradZ >( getName() ); + } ); } @@ -241,67 +239,57 @@ void CompositionalMultiphaseHybridFVM::precomputeData( MeshLevel & mesh, string_ { FlowSolverBase::precomputeData( mesh, regionNames ); - NodeManager const & nodeManager = mesh.getNodeManager(); - FaceManager & faceManager = mesh.getFaceManager(); - - array1d< RAJA::ReduceSum< serialReduce, real64 > > mimFaceGravCoefNumerator; - array1d< RAJA::ReduceSum< serialReduce, real64 > > mimFaceGravCoefDenominator; - mimFaceGravCoefNumerator.resize( faceManager.size() ); - mimFaceGravCoefDenominator.resize( faceManager.size() ); - - // node data - - arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition = nodeManager.referencePosition(); - - // face data - - arrayView1d< real64 const > const & transMultiplier = - faceManager.getField< flow::transMultiplier >(); - - arrayView1d< real64 > const mimFaceGravCoef = - faceManager.getField< flow::mimGravityCoefficient >(); - - ArrayOfArraysView< localIndex const > const & faceToNodes = faceManager.nodeList().toViewConst(); - - real64 const lengthTolerance = m_lengthTolerance; - - mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const, - CellElementSubRegion & subRegion ) + // Pre-compute and initialize face mimeticTransGgradZ once (only for HybridMimetic discretization) { - arrayView2d< real64 const > const & elemCenter = - subRegion.template getReference< array2d< real64 > >( CellElementSubRegion::viewKeyStruct::elementCenterString() ); - string const & permModelName = subRegion.getReference< string >( viewKeyStruct::permeabilityNamesString() ); - arrayView3d< real64 const > const & elemPerm = - getConstitutiveModel< PermeabilityBase >( subRegion, permModelName ).permeability(); - arrayView1d< real64 const > const elemGravCoef = - subRegion.template getReference< array1d< real64 > >( flow::gravityCoefficient::key() ); - arrayView1d< real64 const > const & elemVolume = subRegion.getElementVolume(); - arrayView2d< localIndex const > const & elemToFaces = subRegion.faceList(); - - // here we precompute some quantities (mimFaceFracCoef) used in the FluxKernel to assemble the one-sided gravity term in the transport - // scheme - // This one-sided gravity term is currently always treated with TPFA, as in MRST. - // In the future, I will change that (here and in the FluxKernel) to have a consistent inner product for the gravity term as well - compositionalMultiphaseHybridFVMKernels:: - simpleKernelLaunchSelector< PrecomputeKernel, - mimeticInnerProduct::TPFAInnerProduct >( subRegion.numFacesPerElement(), - subRegion.size(), - faceManager.size(), - nodePosition, - faceToNodes, - elemCenter, - elemVolume, - elemPerm, - elemGravCoef, - elemToFaces, - transMultiplier, - lengthTolerance, - mimFaceGravCoefNumerator.toView(), - mimFaceGravCoefDenominator.toView(), - mimFaceGravCoef ); + DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); + NumericalMethodsManager const & nm = domain.getNumericalMethodManager(); + FiniteVolumeManager const & fvManager = nm.getFiniteVolumeManager(); - } ); + HybridMimeticDiscretization const & hm = fvManager.getHybridMimeticDiscretization( m_discretizationName ); + mimeticInnerProduct::MimeticInnerProductBase const & ip = hm.getReference< mimeticInnerProduct::MimeticInnerProductBase >( HybridMimeticDiscretization::viewKeyStruct::innerProductString() ); + real64 const lengthTolerance = domain.getMeshBody( 0 ).getGlobalLengthScale() * m_lengthTolerance; + forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &, MeshLevel & mesh, string_array const & regionNames ) + { + FaceManager & faceManager = mesh.getFaceManager(); + // Temporary accumulators + array1d< real64 > invSum( faceManager.size() ); invSum.setValues< parallelDevicePolicy<> >( 0.0 ); + array1d< integer > count( faceManager.size() ); count.setValues< parallelDevicePolicy<> >( 0 ); + + NodeManager const & nodeManager = mesh.getNodeManager(); + mesh.getElemManager().forElementSubRegionsComplete< CellElementSubRegion >( regionNames, + [&]( localIndex const, localIndex const er, localIndex const esr, ElementRegionBase const &, + CellElementSubRegion const & subRegion ) + { + GEOS_UNUSED_VAR( er ); + GEOS_UNUSED_VAR( esr ); + string const & permName = subRegion.getReference< string >( viewKeyStruct::permeabilityNamesString() ); + PermeabilityBase const & permeability = getConstitutiveModel< PermeabilityBase >( subRegion, permName ); + PrecomputeMimeticTransGgradZKernel::createAndLaunch< parallelDevicePolicy<> >( ip, + nodeManager, + faceManager, + subRegion, + permeability, + lengthTolerance, + invSum.toView(), + count.toView() ); + } ); + + // Reduce to effective value per face and write to field + arrayView1d< real64 > mimeticTransGgradZ = faceManager.getField< flow::mimeticTransGgradZ >(); + arrayView1d< integer const > ghost = faceManager.ghostRank(); + forAll< parallelDevicePolicy<> >( faceManager.size(), [=] GEOS_HOST_DEVICE ( localIndex const kf ) + { + if( ghost[kf] >= 0 ) + { + return; + } + real64 const s = invSum[kf]; + integer const c = count[kf]; + mimeticTransGgradZ[kf] = (c > 0 && s > 0.0) ? static_cast< real64 >( c ) / s : 0.0; + } ); + } ); + } } void CompositionalMultiphaseHybridFVM::implicitStepSetup( real64 const & time_n, @@ -417,8 +405,8 @@ void CompositionalMultiphaseHybridFVM::assembleFluxTerms( real64 const dt, // get the face-centered depth arrayView1d< real64 const > const & faceGravCoef = faceManager.getField< flow::gravityCoefficient >(); - arrayView1d< real64 const > const & mimFaceGravCoef = - faceManager.getField< flow::mimGravityCoefficient >(); + arrayView1d< real64 const > const & mimeticTransGgradZ = + faceManager.getField< flow::mimeticTransGgradZ >(); // get the face-centered transMultiplier arrayView1d< real64 const > const & transMultiplier = @@ -468,7 +456,7 @@ void CompositionalMultiphaseHybridFVM::assembleFluxTerms( real64 const dt, isBoundaryFaceView, facePres, faceGravCoef, - mimFaceGravCoef, + mimeticTransGgradZ, transMultiplier, compFlowAccessors.get( flow::phaseMobility{} ), compFlowAccessors.get( flow::dPhaseMobility{} ), @@ -809,8 +797,6 @@ void CompositionalMultiphaseHybridFVM::applyFaceDirichletBC( real64 const time_n } ); } - // CRITICAL: Move the SAME array views that were just modified back to device memory - // Don't get new views - use the views that evaluateBCFaceProperties actually modified // evaluateBCFaceProperties uses serialPolicy (host), DirichletFluxKernel uses parallelDevicePolicy (device) facePhaseMob.move( parallelDeviceMemorySpace, false ); facePhaseMassDens.move( parallelDeviceMemorySpace, false ); @@ -980,12 +966,6 @@ void CompositionalMultiphaseHybridFVM::applyFaceDirichletBC( real64 const time_n // Mathematical procedure to enforce prescribed value in Ax = b: // 1. For row i: Zero all entries except diagonal, set A[i,i] = 1, set b[i] = x_spec // 2. For all other rows k: subtract A[k,i] * x_spec from b[k], then set A[k,i] = 0 - // - // Note: Step 2 (removing column influence) should ideally be done, but in practice - // for boundary face DOFs in hybrid FVM, the column entries from interior faces to - // boundary faces are typically zero or minimal because boundary faces don't strongly - // couple to interior equations. The strong coupling is boundary->interior (via fluxes). - // For exact enforcement in non-trivial cases, column zeroing would be needed. if( localRow >= 0 && localRow < localMatrix.numRows() ) { @@ -1009,7 +989,6 @@ void CompositionalMultiphaseHybridFVM::applyFaceDirichletBC( real64 const time_n // Set RHS to the prescribed boundary value (absolute value) localRhs[localRow] = presFace[kf] - presFaceBC[kf]; } - } ); } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp index 22f363f2c22..a8023ba1821 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp @@ -185,13 +185,13 @@ DECLARE_FIELD( gravityCoefficient, WRITE_AND_READ, "Gravity coefficient (dot product of gravity acceleration by gravity vector)" ); -DECLARE_FIELD( mimGravityCoefficient, - "mimGravityCoefficient", +DECLARE_FIELD( mimeticTransGgradZ, + "mimeticTransGgradZ", array1d< real64 >, 0, NOPLOT, WRITE_AND_READ, - "Mimetic gravity coefficient" ); + "Consistent mimetic operator applied to g grad(z) (harmonic average of element contributions)" ); DECLARE_FIELD( macroElementIndex, "macroElementIndex", diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp index d713a3d0a7e..9d35d7c7e76 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp @@ -31,10 +31,12 @@ #include "mesh/ElementRegionManager.hpp" #include "mesh/ObjectManagerBase.hpp" #include "physicsSolvers/PhysicsSolverBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" +#include "finiteVolume/MimeticInnerProductDispatch.hpp" namespace geos @@ -43,6 +45,66 @@ namespace geos namespace compositionalMultiphaseHybridFVMKernels { +//namespace internal +/******************************** Kernel switches ********************************/ + +namespace internal +{ + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorFaceSwitch( T value, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "KernelLaunchSelectorFaceSwitch: type should be integral" ); + + switch( value ) + { + case 4: + { + return lambda( std::integral_constant< int, 4 >{} ); + } + case 5: + { + return lambda( std::integral_constant< int, 5 >{} ); + } + case 6: + { + return lambda( std::integral_constant< int, 6 >{} ); + } + case 7: + { + return lambda( std::integral_constant< int, 7 >{} ); + } + case 8: + { + return lambda( std::integral_constant< int, 8 >{} ); + } + case 9: + { + return lambda( std::integral_constant< int, 9 >{} ); + } + case 10: + { + return lambda( std::integral_constant< int, 10 >{} ); + } + case 11: + { + return lambda( std::integral_constant< int, 11 >{} ); + } + case 12: + { + return lambda( std::integral_constant< int, 12 >{} ); + } + case 13: + { + return lambda( std::integral_constant< int, 13 >{} ); + } + default: + GEOS_ERROR( "Unknown numFacesInElem value: " << value ); + } +} + +} // namespace internal + // struct to specify local and neighbor derivatives struct Pos { @@ -320,7 +382,7 @@ struct AssemblerKernelHelper * @param[in] dPhaseMob the derivatives of the phase mobilities in the element * @param[in] dCompFrac_dCompDens the derivatives of the component fractions wrt component density * @param[in] phaseCompFrac the phase component fractions in the domain - * @param[in] dPhaseCompFrac the derivatives of the phase component fractions wrt pressure and component fractions + * @param[in] dPhaseCompFrac the derivatives of the phase component fractions in the domain wrt pressure and component fractions * @param[in] elemDofNumber the dof numbers of the element in the domain * @param[in] oneSidedVolFlux the volumetric fluxes at this element's faces * @param[in] dOneSidedVolFlux_dPres the derivatives of the vol fluxes wrt to this element's cell centered pressure @@ -341,7 +403,8 @@ struct AssemblerKernelHelper SortedArrayView< localIndex const > const & regionFilter, arrayView1d< globalIndex const > const & faceDofNumber, arrayView1d< integer const > const & isBoundaryFace, - arrayView1d< real64 const > const & mimFaceGravCoef, + arrayView1d< real64 const > const & mimeticTransGgradZ, + arrayView1d< real64 const > const & faceGravCoef, arraySlice1d< localIndex const > const & elemToFaces, real64 const & elemGravCoef, integer const useTotalMassEquation, @@ -355,7 +418,7 @@ struct AssemblerKernelHelper ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, ElementViewConst< arrayView1d< globalIndex const > > const & elemDofNumber, - arraySlice2d< real64 const > const & transMatrixGrav, + arraySlice2d< real64 const > const & transMatrix, real64 const (&oneSidedVolFlux)[ NF ], real64 const (&dOneSidedVolFlux_dPres)[ NF ], real64 const (&dOneSidedVolFlux_dFacePres)[ NF ][ NF ], @@ -526,7 +589,7 @@ struct AssemblerKernel arrayView1d< integer const > const & isBoundaryFace, arrayView1d< real64 const > const & facePres, arrayView1d< real64 const > const & faceGravCoef, - arrayView1d< real64 const > const & mimFaceGravCoef, + arrayView1d< real64 const > const & mimeticTransGgradZ, arraySlice1d< localIndex const > const & elemToFaces, real64 const & elemPres, real64 const & elemGravCoef, @@ -545,7 +608,6 @@ struct AssemblerKernel globalIndex const rankOffset, real64 const & dt, arraySlice2d< real64 const > const & transMatrix, - arraySlice2d< real64 const > const & transMatrixGrav, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); }; @@ -708,6 +770,7 @@ struct FluxKernel * @param[in] rankOffset the offset of this rank * @param[in] lengthTolerance tolerance used in the transmissibility matrix computation * @param[in] dt time step size + * @param[in] transMatrix the transmissibility matrix in this element * @param[inout] matrix the system matrix * @param[inout] rhs the system right-hand side vector */ @@ -727,7 +790,7 @@ struct FluxKernel arrayView1d< integer const > const & isBoundaryFace, arrayView1d< real64 const > const & facePres, arrayView1d< real64 const > const & faceGravCoef, - arrayView1d< real64 const > const & mimFaceGravCoef, + arrayView1d< real64 const > const & mimeticTransGgradZ, arrayView1d< real64 const > const & transMultiplier, ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, @@ -1174,33 +1237,32 @@ struct SolutionCheckKernel }; -/******************************** PrecomputeKernel ********************************/ +/******************************** PrecomputeMimeticTransGgradZKernel ********************************/ -struct PrecomputeKernel +struct PrecomputeMimeticTransGgradZKernel { template< typename IP_TYPE, integer NF > static void launch( localIndex const subRegionSize, - localIndex const faceManagerSize, arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition, ArrayOfArraysView< localIndex const > const & faceToNodes, arrayView2d< real64 const > const & elemCenter, arrayView1d< real64 const > const & elemVolume, arrayView3d< real64 const > const & elemPerm, arrayView1d< real64 const > const & elemGravCoef, + arrayView1d< real64 const > const & faceGravCoef, arrayView2d< localIndex const > const & elemToFaces, arrayView1d< real64 const > const & transMultiplier, real64 const & lengthTolerance, - arrayView1d< RAJA::ReduceSum< serialReduce, real64 > > const & mimFaceGravCoefNumerator, - arrayView1d< RAJA::ReduceSum< serialReduce, real64 > > const & mimFaceGravCoefDenominator, - arrayView1d< real64 > const & mimFaceGravCoef ) + arrayView1d< real64 > const & faceInvSum, + arrayView1d< integer > const & faceCount ) { - forAll< serialPolicy >( subRegionSize, [=] ( localIndex const ei ) + forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const ei ) { - stackArray2d< real64, NF *NF > transMatrix( NF, NF ); + stackArray2d< real64, NF * NF > transMatrix( NF, NF ); - real64 const perm[ 3 ] = { elemPerm[ei][0][0], elemPerm[ei][0][1], elemPerm[ei][0][2] }; + real64 const perm[3] = { elemPerm[ei][0][0], elemPerm[ei][0][1], elemPerm[ei][0][2] }; IP_TYPE::template compute< NF >( nodePosition, transMultiplier, @@ -1212,19 +1274,65 @@ struct PrecomputeKernel lengthTolerance, transMatrix ); - for( integer ifaceLoc = 0; ifaceLoc < NF; ++ifaceLoc ) + real64 const ccGravCoef = elemGravCoef[ei]; + for( integer i = 0; i < NF; ++i ) { - mimFaceGravCoefNumerator[elemToFaces[ei][ifaceLoc]] += elemGravCoef[ei] * transMatrix[ifaceLoc][ifaceLoc]; - mimFaceGravCoefDenominator[elemToFaces[ei][ifaceLoc]] += transMatrix[ifaceLoc][ifaceLoc]; + localIndex const kf = elemToFaces[ei][i]; + + real64 T_g_delta_z = 0.0; + for( integer j = 0; j < NF; ++j ) + { + real64 const fGravCoef = faceGravCoef[elemToFaces[ei][j]]; + real64 const gravCoefDif = ccGravCoef - fGravCoef; + T_g_delta_z += transMatrix[i][j] * gravCoefDif; + } + RAJA::atomicAdd( parallelDeviceAtomic{}, &faceInvSum[kf], 1.0 / LvArray::math::abs( T_g_delta_z ) ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &faceCount[kf], 1 ); } } ); + } - forAll< serialPolicy >( faceManagerSize, [=] ( localIndex const iface ) + template< typename POLICY > + static void + createAndLaunch( mimeticInnerProduct::MimeticInnerProductBase const & ip, + NodeManager const & nodeManager, + FaceManager const & faceManager, + CellElementSubRegion const & subRegion, + constitutive::PermeabilityBase const & permeability, + real64 const lengthTolerance, + arrayView1d< real64 > const & faceInvSum, + arrayView1d< integer > const & faceCount ) + { + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & nodePosition = nodeManager.referencePosition(); + ArrayOfArraysView< localIndex const > const & faceToNodes = faceManager.nodeList().toViewConst(); + arrayView1d< real64 const > const & transMultiplier = faceManager.getField< fields::flow::transMultiplier >(); + arrayView1d< real64 const > const & faceGravCoef = faceManager.getField< fields::flow::gravityCoefficient >(); + + arrayView2d< real64 const > const & elemCenter = subRegion.getElementCenter(); + arrayView1d< real64 const > const & elemVolume = subRegion.getElementVolume(); + arrayView3d< real64 const > const & elemPerm = permeability.permeability(); + arrayView1d< real64 const > const & elemGravCoef = subRegion.getField< fields::flow::gravityCoefficient >(); + arrayView2d< localIndex const > const & elemToFaces = subRegion.faceList(); + + mimeticInnerProductDispatch( ip, [&]( auto const & innerProduct ) { - if( !isZero( mimFaceGravCoefDenominator[iface].get() ) ) + using IP_TYPE = std::remove_const_t< TYPEOFREF( innerProduct ) >; + internal::kernelLaunchSelectorFaceSwitch( subRegion.numFacesPerElement(), [&]( auto NF ) { - mimFaceGravCoef[iface] = mimFaceGravCoefNumerator[iface].get() / mimFaceGravCoefDenominator[iface].get(); - } + PrecomputeMimeticTransGgradZKernel::launch< IP_TYPE, NF() >( subRegion.size(), + nodePosition, + faceToNodes, + elemCenter, + elemVolume, + elemPerm, + elemGravCoef, + faceGravCoef, + elemToFaces, + transMultiplier, + lengthTolerance, + faceInvSum, + faceCount ); + } ); } ); } }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels_impl.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels_impl.hpp index 64f8d7f0d58..3075c22a3e9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels_impl.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels_impl.hpp @@ -619,7 +619,8 @@ AssemblerKernelHelper:: SortedArrayView< localIndex const > const & regionFilter, arrayView1d< globalIndex const > const & faceDofNumber, arrayView1d< integer const > const & isBoundaryFace, - arrayView1d< real64 const > const & mimFaceGravCoef, + arrayView1d< real64 const > const & mimeticTransGgradZ, + arrayView1d< real64 const > const & faceGravCoef, arraySlice1d< localIndex const > const & elemToFaces, real64 const & elemGravCoef, integer const useTotalMassEquation, @@ -633,7 +634,7 @@ AssemblerKernelHelper:: ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, ElementViewConst< arrayView1d< globalIndex const > > const & elemDofNumber, - arraySlice2d< real64 const > const & transMatrixGrav, + arraySlice2d< real64 const > const & transMatrix, real64 const (&oneSidedVolFlux)[ NF ], real64 const (&dOneSidedVolFlux_dPres)[ NF ], real64 const (&dOneSidedVolFlux_dFacePres)[ NF ][ NF ], @@ -704,7 +705,6 @@ AssemblerKernelHelper:: localIndex const neighborDofNumber = elemDofNumber[neighborIds[0]][neighborIds[1]][neighborIds[2]]; // 2) *************** Assemble viscous terms ****************** - // 2.a) Compute the upwinded x_{c, \ell} \rho_{\ell} \frac{\lambda_{\ell}}{\lambda_T} for each phase at this face UpwindingHelper::upwindViscousCoefficient< NC, NP >( localIds, neighborIds, @@ -740,11 +740,23 @@ AssemblerKernelHelper:: dDivMassFluxes_dFaceVars, dofColIndicesElemVars ); - // 3) *************** Assemble buoyancy terms ****************** - real64 const transGravCoef = (localIds[0] != neighborIds[0] || localIds[1] != neighborIds[1] || localIds[2] != neighborIds[2]) - * transMatrixGrav[ifaceLoc][ifaceLoc] * (elemGravCoef - mimFaceGravCoef[elemToFaces[ifaceLoc]]); + // The sign of gFlux_i determines direction for buoyancy w.r.t the consistent inner product. + real64 gFlux_i = 0.0; + for( integer jfaceLoc=0; jfaceLoc 0.0 ) - integer( gFlux_i < 0.0 ); + + // Buoyancy transmissibility applied on ifaceLoc face. The boolean comparison acts + // as a 0/1 mask that disables the buoyancy flux for domain boundaries. + real64 const transGravCoef = sign * (localIds[0] != neighborIds[0] || localIds[1] != neighborIds[1] || localIds[2] != neighborIds[2]) * mimeticTransGgradZ[elemToFaces[ifaceLoc]]; // 3.a) Compute the upwinded x_{c, \ell} \rho_{\ell} \frac{\lambda_{\ell}\lambda_m}{\lambda_T} // and (\rho_{\ell} - \rho_m) g \Delta z for each phase at this face @@ -1108,7 +1120,7 @@ AssemblerKernel:: arrayView1d< integer const > const & isBoundaryFace, arrayView1d< real64 const > const & facePres, arrayView1d< real64 const > const & faceGravCoef, - arrayView1d< real64 const > const & mimFaceGravCoef, + arrayView1d< real64 const > const & mimeticTransGgradZ, arraySlice1d< localIndex const > const & elemToFaces, real64 const & elemPres, real64 const & elemGravCoef, @@ -1127,7 +1139,6 @@ AssemblerKernel:: globalIndex const rankOffset, real64 const & dt, arraySlice2d< real64 const > const & transMatrix, - arraySlice2d< real64 const > const & transMatrixGrav, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ) { @@ -1184,7 +1195,8 @@ AssemblerKernel:: regionFilter, faceDofNumber, isBoundaryFace, - mimFaceGravCoef, + mimeticTransGgradZ, + faceGravCoef, elemToFaces, elemGravCoef, useTotalMassEquation, @@ -1198,7 +1210,7 @@ AssemblerKernel:: phaseCompFrac, dPhaseCompFrac, elemDofNumber, - transMatrixGrav, + transMatrix, oneSidedVolFlux, dOneSidedVolFlux_dPres, dOneSidedVolFlux_dFacePres, @@ -1243,7 +1255,7 @@ FluxKernel:: arrayView1d< integer const > const & isBoundaryFace, arrayView1d< real64 const > const & facePres, arrayView1d< real64 const > const & faceGravCoef, - arrayView1d< real64 const > const & mimFaceGravCoef, + arrayView1d< real64 const > const & mimeticTransGgradZ, arrayView1d< real64 const > const & transMultiplier, ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, @@ -1293,8 +1305,6 @@ FluxKernel:: { // transmissibility matrix stackArray2d< real64, NF *NF > transMatrix( NF, NF ); - stackArray2d< real64, NF *NF > transMatrixGrav( NF, NF ); - real64 const perm[ 3 ] = { elemPerm[ei][0][0], elemPerm[ei][0][1], elemPerm[ei][0][2] }; // recompute the local transmissibility matrix at each iteration @@ -1309,19 +1319,6 @@ FluxKernel:: lengthTolerance, transMatrix ); - // currently the gravity term in the transport scheme is treated as in MRST, that is, always with TPFA - // this is why below we have to recompute the TPFA transmissibility in addition to the transmissibility matrix above - // TODO: treat the gravity term with a consistent inner product - mimeticInnerProduct::TPFAInnerProduct::compute< NF >( nodePosition, - transMultiplier, - faceToNodes, - elemToFaces[ei], - elemCenter[ei], - elemVolume[ei], - perm, - lengthTolerance, - transMatrixGrav ); - // perform flux assembly in this element compositionalMultiphaseHybridFVMKernels::AssemblerKernel::compute< NF, NC, NP >( er, esr, ei, regionFilter, @@ -1333,7 +1330,7 @@ FluxKernel:: isBoundaryFace, facePres, faceGravCoef, - mimFaceGravCoef, + mimeticTransGgradZ, elemToFaces[ei], elemPres[ei], elemGravCoef[ei], @@ -1352,7 +1349,6 @@ FluxKernel:: rankOffset, dt, transMatrix, - transMatrixGrav, localMatrix, localRhs ); } );