diff --git a/.integrated_tests.yaml b/.integrated_tests.yaml index 2920bb10e8d..71364ebb802 100644 --- a/.integrated_tests.yaml +++ b/.integrated_tests.yaml @@ -1,6 +1,6 @@ baselines: bucket: geosx - baseline: integratedTests/baseline_integratedTests-pr3413-8558-9f4af7c + baseline: integratedTests/baseline_integratedTests-pr3374-8621-bbb3cb2 allow_fail: all: '' diff --git a/BASELINE_NOTES.md b/BASELINE_NOTES.md index 896431de55b..3af18f0dec8 100644 --- a/BASELINE_NOTES.md +++ b/BASELINE_NOTES.md @@ -6,6 +6,18 @@ 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 #3374 (2024-11-09) +==================== +Bugfix for gravity treatment in flux for thermal. + +PR #3372 (2024-11-09) +==================== +Fix a bug related to mass and energy updates for poromechanics. + +PR #3426 (2024-11-08) +==================== +Bugfix: reset accumulation in fracture when time step cut occurs in hydrofrac solver. + PR #3413 (2024-11-07) ==================== Add tests for poro-thermo-plastic model. diff --git a/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml b/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml index c775276de50..cc461b52ba3 100644 --- a/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml +++ b/inputFiles/hydraulicFracturing/kgdEdgeBased_C3D6_base.xml @@ -17,7 +17,7 @@ + lineSearchAction="None"/> diff --git a/inputFiles/hydraulicFracturing/kgdNodeBased_C3D6_base.xml b/inputFiles/hydraulicFracturing/kgdNodeBased_C3D6_base.xml index 07c0fbf8373..d7fbbd5d077 100644 --- a/inputFiles/hydraulicFracturing/kgdNodeBased_C3D6_base.xml +++ b/inputFiles/hydraulicFracturing/kgdNodeBased_C3D6_base.xml @@ -18,7 +18,7 @@ + lineSearchAction="None"/> diff --git a/src/coreComponents/constitutive/CMakeLists.txt b/src/coreComponents/constitutive/CMakeLists.txt index cc9093e1174..c6e3fd499e9 100644 --- a/src/coreComponents/constitutive/CMakeLists.txt +++ b/src/coreComponents/constitutive/CMakeLists.txt @@ -172,7 +172,6 @@ set( constitutive_headers thermalConductivity/MultiPhaseVolumeWeightedThermalConductivity.hpp thermalConductivity/SinglePhaseThermalConductivity.hpp thermalConductivity/SinglePhaseThermalConductivityBase.hpp - thermalConductivity/SinglePhaseThermalConductivityFields.hpp thermalConductivity/SinglePhaseThermalConductivitySelector.hpp thermalConductivity/ThermalConductivityFields.hpp ) diff --git a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp index 7d54ed3e3c4..580a965061b 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp +++ b/src/coreComponents/constitutive/fluid/multifluid/MultiFluidSelector.hpp @@ -14,7 +14,7 @@ */ /** - * @file multiFluidSelector.hpp + * @file MultiFluidSelector.hpp */ #ifndef GEOS_CONSTITUTIVE_FLUID_MULTIFLUIDSELECTOR_HPP_ #define GEOS_CONSTITUTIVE_FLUID_MULTIFLUIDSELECTOR_HPP_ diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp index d4760a4d871..2ee0fa4a908 100644 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp +++ b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.cpp @@ -19,7 +19,6 @@ #include "SinglePhaseThermalConductivityBase.hpp" #include "ThermalConductivityFields.hpp" -#include "SinglePhaseThermalConductivityFields.hpp" namespace geos { diff --git a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp b/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp deleted file mode 100644 index 267183f85c3..00000000000 --- a/src/coreComponents/constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseThermalConductivityFields.hpp - */ - -#ifndef GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITYFIELDS_HPP_ -#define GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITYFIELDS_HPP_ - -#include "constitutive/relativePermeability/layouts.hpp" -#include "mesh/MeshFields.hpp" - -namespace geos -{ - -namespace fields -{ - -namespace thermalconductivity -{ - -DECLARE_FIELD( dEffectiveConductivity_dPorosity, - "dEffectiveConductivity_dPorosity", - array3d< real64 >, - 0, - NOPLOT, - NO_WRITE, - "Derivative of effective conductivity with respect to porosity" ); - -} - -} - -} - -#endif // GEOS_CONSTITUTIVE_SINGLEPHASE_THERMALCONDUCTIVITY_THERMALCONDUCTIVITYFIELDS_HPP_ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt index 8fae050093f..651d9135e08 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt +++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt @@ -1,59 +1,106 @@ # Specify solver headers set( physicsSolvers_headers ${physicsSolvers_headers} + fluidFlow/FlowSolverBase.hpp + fluidFlow/FlowSolverBaseFields.hpp fluidFlow/CompositionalMultiphaseBase.hpp fluidFlow/CompositionalMultiphaseBaseFields.hpp fluidFlow/CompositionalMultiphaseStatistics.hpp - fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp - fluidFlow/kernels/ThermalCompositionalMultiphaseBaseKernels.hpp fluidFlow/CompositionalMultiphaseFVM.hpp - fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp - fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp - fluidFlow/kernels/ThermalCompositionalMultiphaseFVMKernels.hpp fluidFlow/CompositionalMultiphaseHybridFVM.hpp - fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.hpp fluidFlow/CompositionalMultiphaseUtilities.hpp fluidFlow/ReactiveCompositionalMultiphaseOBL.hpp fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp - fluidFlow/kernels/ReactiveCompositionalMultiphaseOBLKernels.hpp - fluidFlow/FlowSolverBase.hpp - fluidFlow/FlowSolverBaseFields.hpp - fluidFlow/kernels/FlowSolverBaseKernels.hpp - fluidFlow/kernels/FluxKernelsHelper.hpp - fluidFlow/kernels/HybridFVMHelperKernels.hpp fluidFlow/SourceFluxStatistics.hpp - fluidFlow/proppantTransport/ProppantTransport.hpp - fluidFlow/proppantTransport/ProppantTransportFields.hpp - fluidFlow/proppantTransport/ProppantTransportKernels.hpp fluidFlow/SinglePhaseBase.hpp fluidFlow/SinglePhaseBaseFields.hpp - fluidFlow/kernels/SinglePhaseBaseKernels.hpp fluidFlow/SinglePhaseStatistics.hpp fluidFlow/SinglePhaseFVM.hpp - fluidFlow/kernels/SinglePhaseFVMKernels.hpp fluidFlow/SinglePhaseHybridFVM.hpp - fluidFlow/kernels/SinglePhaseHybridFVMKernels.hpp fluidFlow/SinglePhaseProppantBase.hpp - fluidFlow/kernels/SinglePhaseProppantBaseKernels.hpp - fluidFlow/kernels/SinglePhaseProppantFluxKernels.hpp - fluidFlow/kernels/StabilizedCompositionalMultiphaseFVMKernels.hpp - fluidFlow/kernels/StabilizedSinglePhaseFVMKernels.hpp fluidFlow/StencilAccessors.hpp fluidFlow/StencilDataCollection.hpp - fluidFlow/kernels/ThermalSinglePhaseBaseKernels.hpp - fluidFlow/kernels/ThermalSinglePhaseFVMKernels.hpp fluidFlow/LogLevelsInfo.hpp + fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp + fluidFlow/kernels/StencilWeightsUpdateKernel.hpp + fluidFlow/kernels/HybridFVMHelperKernels.hpp + fluidFlow/kernels/singlePhase/AccumulationKernels.hpp + fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp + fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp + fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp + fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp + fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp + fluidFlow/kernels/singlePhase/MobilityKernel.hpp + fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp + fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp + fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp + fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp + fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp + fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/StatisticsKernel.hpp + fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp + fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp + fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp + fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.hpp + fluidFlow/kernels/compositional/AccumulationKernel.hpp + fluidFlow/kernels/compositional/AquiferBCKernel.hpp + fluidFlow/kernels/compositional/PPUPhaseFlux.hpp + fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp + fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp + fluidFlow/kernels/compositional/CFLKernel.hpp + fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp + fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp + fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp + fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp + fluidFlow/kernels/compositional/FluidUpdateKernel.hpp + fluidFlow/kernels/compositional/FluidUpdateKernel.hpp + fluidFlow/kernels/compositional/FluxComputeKernel.hpp + fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp + fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp + fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp + fluidFlow/kernels/compositional/IHUPhaseFlux.hpp + fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp + fluidFlow/kernels/compositional/PhaseComponentFlux.hpp + fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp + fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp + fluidFlow/kernels/compositional/PotGrad.hpp + fluidFlow/kernels/compositional/PPUPhaseFlux.hpp + fluidFlow/kernels/compositional/PropertyKernelBase.hpp + fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp + fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp + fluidFlow/kernels/compositional/ResidualNormKernel.hpp + fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp + fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp + fluidFlow/kernels/compositional/SolutionCheckKernel.hpp + fluidFlow/kernels/compositional/SolutionScalingKernel.hpp + fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp + fluidFlow/kernels/compositional/StatisticsKernel.hpp + fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp + fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp + fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp + fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp + fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp + fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp + fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp + fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp + fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp fluidFlow/wells/CompositionalMultiphaseWell.hpp fluidFlow/wells/CompositionalMultiphaseWellFields.hpp - fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp fluidFlow/wells/SinglePhaseWell.hpp fluidFlow/wells/SinglePhaseWellFields.hpp - fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp fluidFlow/wells/WellConstants.hpp fluidFlow/wells/WellControls.hpp fluidFlow/wells/WellSolverBase.hpp fluidFlow/wells/WellSolverBaseFields.hpp fluidFlow/wells/LogLevelsInfo.hpp + fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp + fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp + fluidFlow/proppantTransport/ProppantTransport.hpp + fluidFlow/proppantTransport/ProppantTransportFields.hpp + fluidFlow/proppantTransport/ProppantTransportKernels.hpp PARENT_SCOPE ) # Specify solver sources @@ -62,27 +109,29 @@ set( physicsSolvers_sources fluidFlow/CompositionalMultiphaseBase.cpp fluidFlow/CompositionalMultiphaseFVM.cpp fluidFlow/CompositionalMultiphaseStatistics.cpp - fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.cpp fluidFlow/CompositionalMultiphaseHybridFVM.cpp - fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.cpp fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp fluidFlow/FlowSolverBase.cpp - fluidFlow/proppantTransport/ProppantTransport.cpp - fluidFlow/proppantTransport/ProppantTransportKernels.cpp fluidFlow/SinglePhaseBase.cpp fluidFlow/SinglePhaseStatistics.cpp fluidFlow/SinglePhaseFVM.cpp fluidFlow/SinglePhaseHybridFVM.cpp fluidFlow/SinglePhaseProppantBase.cpp - fluidFlow/kernels/SinglePhaseProppantFluxKernels.cpp fluidFlow/SourceFluxStatistics.cpp fluidFlow/StencilDataCollection.cpp + fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp + fluidFlow/kernels/compositional/AquiferBCKernel.cpp + fluidFlow/kernels/compositional/CFLKernel.cpp + fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp + fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.cpp fluidFlow/wells/CompositionalMultiphaseWell.cpp fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp fluidFlow/wells/SinglePhaseWell.cpp fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp fluidFlow/wells/WellControls.cpp fluidFlow/wells/WellSolverBase.cpp + fluidFlow/proppantTransport/ProppantTransport.cpp + fluidFlow/proppantTransport/ProppantTransportKernels.cpp PARENT_SCOPE ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index 464785fcaba..08e7176fdbe 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp @@ -36,14 +36,24 @@ #include "fieldSpecification/AquiferBoundaryCondition.hpp" #include "fieldSpecification/EquilibriumInitialCondition.hpp" #include "fieldSpecification/SourceFluxBoundaryCondition.hpp" -#include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp" // TODO this should not be here -#include "physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/SourceFluxStatistics.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp" #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" @@ -1410,7 +1420,7 @@ void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( Dom if( m_isThermal ) { thermalCompositionalMultiphaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -1425,7 +1435,7 @@ void CompositionalMultiphaseBase::assembleAccumulationAndVolumeBalanceTerms( Dom else { isothermalCompositionalMultiphaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp index 5cb1ecf2a15..784c7810169 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.cpp @@ -36,12 +36,25 @@ #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/StabilizedCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/DissipationCompositionalMultiphaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp" namespace geos { @@ -171,7 +184,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, if( m_isThermal ) { thermalCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -190,7 +203,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, if( m_dbcParams.useDBC ) { dissipationCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -213,7 +226,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, else { isothermalCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -237,7 +250,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, if( m_isThermal ) { thermalCompositionalMultiphaseFVMKernels:: - DiffusionDispersionFaceBasedAssemblyKernelFactory:: + DiffusionDispersionFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -255,7 +268,7 @@ void CompositionalMultiphaseFVM::assembleFluxTerms( real64 const dt, else { isothermalCompositionalMultiphaseFVMKernels:: - DiffusionDispersionFaceBasedAssemblyKernelFactory:: + DiffusionDispersionFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -304,7 +317,7 @@ void CompositionalMultiphaseFVM::assembleStabilizedFluxTerms( real64 const dt, // Thermal implementation not supported yet stabilizedCompositionalMultiphaseFVMKernels:: - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -499,7 +512,7 @@ real64 CompositionalMultiphaseFVM::scalingForSystemSolution( DomainPartition & d auto const subRegionData = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxRelativeTempChange, @@ -518,7 +531,7 @@ real64 CompositionalMultiphaseFVM::scalingForSystemSolution( DomainPartition & d localSolution, temperatureOffset ) : isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, @@ -638,10 +651,8 @@ bool CompositionalMultiphaseFVM::checkSystemSolution( DomainPartition & domain, m_scalingType, scalingFactor, pressure, - compDens, pressureScalingFactor, - compDensScalingFactor, dofManager.rankOffset(), m_numComponents, @@ -1025,7 +1036,7 @@ void CompositionalMultiphaseFVM::applyFaceDirichletBC( real64 const time_n, { //todo (jafranc) extend upwindScheme name if satisfied in isothermalCase thermalCompositionalMultiphaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), @@ -1043,7 +1054,7 @@ void CompositionalMultiphaseFVM::applyFaceDirichletBC( real64 const time_n, else { isothermalCompositionalMultiphaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numComponents, m_numPhases, dofManager.rankOffset(), diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp index 4d85ccd30ab..bedfa0c3261 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp @@ -30,8 +30,11 @@ #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp" /** * @namespace the geos namespace that encapsulates the majority of the code @@ -451,7 +454,7 @@ real64 CompositionalMultiphaseHybridFVM::scalingForSystemSolution( DomainPartiti arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::flow::globalCompDensityScalingFactor >(); auto const subRegionData = isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp index b485cc60657..1aea8723fd8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp @@ -19,19 +19,15 @@ #include "CompositionalMultiphaseStatistics.hpp" +#include "mesh/DomainPartition.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" -#include "finiteVolume/FiniteVolumeManager.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" -#include "mainInterface/ProblemManager.hpp" -#include "physicsSolvers/PhysicsSolverManager.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" #include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp index 13e98e59f00..f803e7c7e1e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.cpp @@ -32,8 +32,8 @@ #include "finiteVolume/FluxApproximationBase.hpp" #include "mesh/DomainPartition.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/FlowSolverBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp" +#include "physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp" namespace geos { @@ -709,14 +709,13 @@ void FlowSolverBase::saveAquiferConvergedState( real64 const & time, elemManager.constructFieldAccessor< fields::flow::gravityCoefficient >(); gravCoef.setName( getName() + "/accessors/" + fields::flow::gravityCoefficient::key() ); - real64 const targetSetSumFluxes = - fluxKernelsHelper::AquiferBCKernel::sumFluxes( stencil, - aquiferBCWrapper, - pressure.toNestedViewConst(), - pressure_n.toNestedViewConst(), - gravCoef.toNestedViewConst(), - time, - dt ); + real64 const targetSetSumFluxes = sumAquiferFluxes( stencil, + aquiferBCWrapper, + pressure.toNestedViewConst(), + pressure_n.toNestedViewConst(), + gravCoef.toNestedViewConst(), + time, + dt ); localIndex const aquiferIndex = aquiferNameToAquiferId.at( bc.getName() ); localSumFluxes[aquiferIndex] += targetSetSumFluxes; @@ -744,6 +743,49 @@ void FlowSolverBase::saveAquiferConvergedState( real64 const & time, } ); } +/** + * @brief Function to sum the aquiferBC fluxes (as later save them) at the end of the time step + * This function is applicable for both single-phase and multiphase flow + */ +real64 +FlowSolverBase::sumAquiferFluxes( BoundaryStencil const & stencil, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & presOld, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + real64 const & timeAtBeginningOfStep, + real64 const & dt ) +{ + using Order = BoundaryStencil::Order; + + BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); + BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); + + RAJA::ReduceSum< parallelDeviceReduce, real64 > targetSetSumFluxes( 0.0 ); + + forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + localIndex const er = seri( iconn, Order::ELEM ); + localIndex const esr = sesri( iconn, Order::ELEM ); + localIndex const ei = sefi( iconn, Order::ELEM ); + real64 const areaFraction = weight( iconn, Order::ELEM ); + + // compute the aquifer influx rate using the pressure influence function and the aquifer props + real64 dAquiferVolFlux_dPres = 0.0; + real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, + dt, + pres[er][esr][ei], + presOld[er][esr][ei], + gravCoef[er][esr][ei], + areaFraction, + dAquiferVolFlux_dPres ); + targetSetSumFluxes += aquiferVolFlux; + } ); + return targetSetSumFluxes.get(); +} + void FlowSolverBase::prepareStencilWeights( DomainPartition & domain ) const { forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp index ae1054fdd89..6b65e91e979 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/FlowSolverBase.hpp @@ -22,6 +22,8 @@ #include "physicsSolvers/PhysicsSolverBase.hpp" #include "common/Units.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "fieldSpecification/AquiferBoundaryCondition.hpp" namespace geos { @@ -34,6 +36,9 @@ namespace geos */ class FlowSolverBase : public PhysicsSolverBase { + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + public: /// String used to form the solverName used to register single-physics solvers in CoupledSolver @@ -160,6 +165,14 @@ class FlowSolverBase : public PhysicsSolverBase void enableLaggingFractureStencilWeightsUpdate(){ m_isLaggingFractureStencilWeightsUpdate = 1; }; + real64 sumAquiferFluxes( BoundaryStencil const & stencil, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & presOld, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + real64 const & timeAtBeginningOfStep, + real64 const & dt ); + protected: /** diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp index df64cbd846c..3d8143e0d83 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp @@ -32,7 +32,7 @@ #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBLFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/ReactiveCompositionalMultiphaseOBLKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp" namespace geos @@ -737,7 +737,7 @@ void ReactiveCompositionalMultiphaseOBL::assembleFluxTerms( real64 const dt, { typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); - FaceBasedAssemblyKernelFactory:: + FluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_numPhases, m_numComponents, m_enableEnergyBalance, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp index 1acf5ced456..8261e822868 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.cpp @@ -40,8 +40,15 @@ #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp" namespace geos @@ -258,7 +265,7 @@ void SinglePhaseBase::updateFluidModel( ObjectManagerBase & dataGroup ) const constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - thermalSinglePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); + singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); } ); } @@ -368,16 +375,16 @@ void SinglePhaseBase::updateMobility( ObjectManagerBase & dataGroup ) const ThermalFluidPropViews thermalFluidProps = getThermalFluidProperties( fluid ); - thermalSinglePhaseBaseKernels::MobilityKernel::launch< parallelDevicePolicy<> >( dataGroup.size(), - fluidProps.dens, - fluidProps.dDens_dPres, - thermalFluidProps.dDens_dTemp, - fluidProps.visc, - fluidProps.dVisc_dPres, - thermalFluidProps.dVisc_dTemp, - mob, - dMob_dPres, - dMob_dTemp ); + singlePhaseBaseKernels::MobilityKernel::launch< parallelDevicePolicy<> >( dataGroup.size(), + fluidProps.dens, + fluidProps.dDens_dPres, + thermalFluidProps.dDens_dTemp, + fluidProps.visc, + fluidProps.dVisc_dPres, + thermalFluidProps.dVisc_dTemp, + mob, + dMob_dPres, + dMob_dTemp ); } else { @@ -1328,7 +1335,7 @@ real64 SinglePhaseBase::scalingForSystemSolution( DomainPartition & domain, arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); auto const subRegionData = - singlePhaseBaseKernels::ScalingForSystemSolutionKernel:: + singlePhaseBaseKernels::SolutionScalingKernel:: launch< parallelDevicePolicy<> >( localSolution, rankOffset, dofNumber, ghostRank, m_maxAbsolutePresChange ); scalingFactor = std::min( scalingFactor, subRegionData.first ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp index e32196fc9f1..bf1cd19eadd 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseBase.hpp @@ -21,8 +21,8 @@ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASE_HPP_ #include "physicsSolvers/fluidFlow/FlowSolverBase.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" @@ -446,7 +446,7 @@ void SinglePhaseBase::accumulationAssemblyLaunch( DofManager const & dofManager, if( m_isThermal ) { thermalSinglePhaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, subRegion, @@ -458,7 +458,7 @@ void SinglePhaseBase::accumulationAssemblyLaunch( DofManager const & dofManager, else { singlePhaseBaseKernels:: - ElementBasedAssemblyKernelFactory:: + AccumulationKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, subRegion, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp index e69e9d9994a..b87ce6bcf75 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseFVM.cpp @@ -33,12 +33,16 @@ #include "fieldSpecification/AquiferBoundaryCondition.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/StabilizedSinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseProppantFluxKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp" @@ -148,29 +152,17 @@ real64 SinglePhaseFVM< BASE >::calculateResidualNorm( real64 const & GEOS_UNUSED real64 subRegionResidualNorm[numNorm]{}; real64 subRegionResidualNormalizer[numNorm]{}; - string const & fluidName = subRegion.template getReference< string >( BASE::viewKeyStruct::fluidNamesString() ); - SingleFluidBase const & fluid = PhysicsSolverBase::getConstitutiveModel< SingleFluidBase >( subRegion, fluidName ); - // step 1: compute the norm in the subRegion if( m_isThermal ) { - string const & solidName = subRegion.template getReference< string >( BASE::viewKeyStruct::solidNamesString() ); - CoupledSolidBase const & solid = PhysicsSolverBase::getConstitutiveModel< CoupledSolidBase >( subRegion, solidName ); - - string const & solidInternalEnergyName = subRegion.template getReference< string >( BASE::viewKeyStruct::solidInternalEnergyNamesString() ); - SolidInternalEnergy const & solidInternalEnergy = PhysicsSolverBase::getConstitutiveModel< SolidInternalEnergy >( subRegion, solidInternalEnergyName ); - - thermalSinglePhaseBaseKernels:: + singlePhaseBaseKernels:: ResidualNormKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( normType, rankOffset, dofKey, localRhs, subRegion, - fluid, - solid, - solidInternalEnergy, m_nonlinearSolverParameters.m_minNormalizer, subRegionResidualNorm, subRegionResidualNormalizer ); @@ -328,26 +320,26 @@ void SinglePhaseFVM<>::assembleFluxTerms( real64 const dt, if( m_isThermal ) { thermalSinglePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } else { singlePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } @@ -381,14 +373,14 @@ void SinglePhaseFVM< SinglePhaseBase >::assembleStabilizedFluxTerms( real64 cons typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); // No thermal support yet - stabilizedSinglePhaseFVMKernels::FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + stabilizedSinglePhaseFVMKernels::FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } ); } ); @@ -425,9 +417,9 @@ void SinglePhaseFVM< SinglePhaseProppantBase >::assembleFluxTerms( real64 const { typename TYPEOFREF( stencil ) ::KernelWrapper stencilWrapper = stencil.createKernelWrapper(); - typename FaceBasedAssemblyKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, getName() ); - typename FaceBasedAssemblyKernelBase::SlurryFluidAccessors fluidAccessors( elemManager, getName() ); - typename FaceBasedAssemblyKernelBase::ProppantPermeabilityAccessors permAccessors( elemManager, getName() ); + typename FluxComputeKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, getName() ); + typename FluxComputeKernelBase::SlurryFluidAccessors fluidAccessors( elemManager, getName() ); + typename FluxComputeKernelBase::ProppantPermeabilityAccessors permAccessors( elemManager, getName() ); singlePhaseProppantFluxKernels::FaceElementFluxKernel::launch( stencilWrapper, dt, @@ -490,26 +482,26 @@ void SinglePhaseFVM< BASE >::assembleEDFMFluxTerms( real64 const GEOS_UNUSED_PAR if( m_isThermal ) { thermalSinglePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } else { singlePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } } ); @@ -579,26 +571,26 @@ void SinglePhaseFVM< BASE >::assembleHydrofracFluxTerms( real64 const GEOS_UNUSE if( m_isThermal ) { thermalSinglePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } else { singlePhaseFVMKernels:: - FaceBasedAssemblyKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), - dofKey, - this->getName(), - mesh.getElemManager(), - stencilWrapper, - dt, - localMatrix.toViewConstSizes(), - localRhs.toView() ); + FluxComputeKernelFactory::createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), + dofKey, + this->getName(), + mesh.getElemManager(), + stencilWrapper, + dt, + localMatrix.toViewConstSizes(), + localRhs.toView() ); } } ); @@ -787,7 +779,7 @@ void SinglePhaseFVM< BASE >::applyFaceDirichletBC( real64 const time_n, SingleFluidBase & fluidBase = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); thermalSinglePhaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, this->getName(), @@ -848,7 +840,7 @@ void SinglePhaseFVM< BASE >::applyFaceDirichletBC( real64 const time_n, BoundaryStencilWrapper const stencilWrapper = stencil.createKernelWrapper(); singlePhaseFVMKernels:: - DirichletFaceBasedAssemblyKernelFactory:: + DirichletFluxComputeKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(), dofKey, this->getName(), @@ -903,8 +895,8 @@ void SinglePhaseFVM<>::applyAquiferBC( real64 const time, elemManager.constructArrayViewAccessor< globalIndex, 1 >( elemDofKey ); elemDofNumber.setName( this->getName() + "/accessors/" + elemDofKey ); - typename FaceBasedAssemblyKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, this->getName() ); - typename FaceBasedAssemblyKernelBase::SinglePhaseFluidAccessors fluidAccessors( elemManager, this->getName() ); + typename FluxComputeKernelBase::SinglePhaseFlowAccessors flowAccessors( elemManager, this->getName() ); + typename FluxComputeKernelBase::SinglePhaseFluidAccessors fluidAccessors( elemManager, this->getName() ); fsManager.apply< FaceManager, AquiferBoundaryCondition >( time + dt, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp index b9bfd4d43de..233eb1d1363 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseHybridFVM.cpp @@ -23,12 +23,16 @@ #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" #include "fieldSpecification/AquiferBoundaryCondition.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" +#include "discretizationMethods/NumericalMethodsManager.hpp" +#include "finiteVolume/FiniteVolumeManager.hpp" #include "finiteVolume/HybridMimeticDiscretization.hpp" #include "finiteVolume/MimeticInnerProductDispatch.hpp" #include "mainInterface/ProblemManager.hpp" +#include "mesh/DomainPartition.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseHybridFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp" /** diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp index 8019edb5d63..0a5ccd5d41e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseProppantBase.cpp @@ -20,6 +20,7 @@ #include "SinglePhaseProppantBase.hpp" +#include "mesh/DomainPartition.hpp" #include "constitutive/ConstitutivePassThru.hpp" #include "constitutive/fluid/singlefluid/SlurryFluidSelector.hpp" #include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" @@ -27,7 +28,7 @@ #include "constitutive/solid/ProppantSolid.hpp" #include "constitutive/solid/porosity/ProppantPorosity.hpp" #include "physicsSolvers/fluidFlow/proppantTransport/ProppantTransportFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseProppantBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp" namespace geos { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp index 3b08616102f..fca8f4cfc99 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/SinglePhaseStatistics.cpp @@ -19,12 +19,13 @@ #include "SinglePhaseStatistics.hpp" +#include "mesh/DomainPartition.hpp" #include "mainInterface/ProblemManager.hpp" #include "physicsSolvers/PhysicsSolverManager.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp" #include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp index 8aff3af7d74..c3eb3805be3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp @@ -14,15 +14,13 @@ */ /** - * @file CompositionalMultiphaseHybridFVMHelperKernels.hpp + * @file HybridFVMHelperKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMUPWINDINGHELPERKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMUPWINDINGHELPERKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMHELPERKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMHELPERKERNELS_HPP #include "common/DataTypes.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "mesh/MeshLevel.hpp" namespace geos { @@ -91,4 +89,4 @@ struct CellConnectivity } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASEHYBRIDFVMUPWINDINGHELPERKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_HYBRIDFVMHELPERKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp deleted file mode 100644 index 3af97cde06b..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp +++ /dev/null @@ -1,2508 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file IsothermalCompositionalMultiphaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP - -#include "codingUtilities/Utilities.hpp" -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/solid/CoupledSolidBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "functions/TableFunction.hpp" -#include "mesh/ElementSubRegionBase.hpp" -#include "mesh/ObjectManagerBase.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" -#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" -#include "physicsSolvers/KernelLaunchSelectors.hpp" - -namespace geos -{ - - -namespace isothermalCompositionalMultiphaseBaseKernels -{ - -static constexpr real64 minDensForDivision = 1e-10; - -enum class ElementBasedAssemblyKernelFlags -{ - SimpleAccumulation = 1 << 0, // 1 - TotalMassEquation = 1 << 1, // 2 - /// Add more flags like that if needed: - // Flag3 = 1 << 2, // 4 - // Flag4 = 1 << 3, // 8 - // Flag5 = 1 << 4, // 16 - // Flag6 = 1 << 5, // 32 - // Flag7 = 1 << 6, // 64 - // Flag8 = 1 << 7 //128 -}; - -/******************************** PropertyKernelBase ********************************/ - -/** - * @class PropertyKernelBase - * @tparam NUM_COMP number of fluid components - * @brief Define the base interface for the property update kernels - */ -template< integer NUM_COMP > -class PropertyKernelBase -{ -public: - - /// Compile time value for the number of components - static constexpr integer numComp = NUM_COMP; - - /** - * @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 the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - kernelComponent.compute( ei ); - } ); - } - - /** - * @brief Performs the kernel launch on a sorted array - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] targetSet the indices of the elements in which we compute the property - * @param[inout] kernelComponent the kernel component providing access to the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - KERNEL_TYPE const & kernelComponent ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) - { - localIndex const ei = targetSet[ i ]; - kernelComponent.compute( ei ); - } ); - } - -}; - -namespace internal -{ - - - -template< typename T, typename LAMBDA > -void kernelLaunchSelectorCompSwitch( T value, LAMBDA && lambda ) -{ - static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: type should be integral" ); - - switch( value ) - { - case 1: - { lambda( std::integral_constant< T, 1 >() ); return; } - case 2: - { lambda( std::integral_constant< T, 2 >() ); return; } - case 3: - { lambda( std::integral_constant< T, 3 >() ); return; } - case 4: - { lambda( std::integral_constant< T, 4 >() ); return; } - case 5: - { lambda( std::integral_constant< T, 5 >() ); return; } - default: - { GEOS_ERROR( "Unsupported number of components: " << value ); } - } -} - -} // namespace internal - - -/******************************** GlobalComponentFractionKernel ********************************/ - -/** - * @class GlobalComponentFractionKernel - * @tparam NUM_COMP number of fluid components - * @brief Define the interface for the update kernel in charge of computing the phase volume fractions - */ -template< integer NUM_COMP > -class GlobalComponentFractionKernel : public PropertyKernelBase< NUM_COMP > -{ -public: - - using Base = PropertyKernelBase< NUM_COMP >; - using Base::numComp; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - GlobalComponentFractionKernel( ObjectManagerBase & subRegion ) - : Base(), - m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), - m_compFrac( subRegion.getField< fields::flow::globalCompFraction >() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ) - {} - - /** - * @brief Compute the phase volume fractions 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] phaseVolFractionKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void compute( localIndex const ei, - FUNC && compFractionKernelOp = NoOpFunc{} ) const - { - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; - arraySlice1d< real64, compflow::USD_COMP - 1 > const compFrac = m_compFrac[ei]; - arraySlice2d< real64, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - - real64 totalDensity = 0.0; - - for( integer ic = 0; ic < numComp; ++ic ) - { - totalDensity += compDens[ic]; - } - - real64 const totalDensityInv = 1.0 / totalDensity; - - for( integer ic = 0; ic < numComp; ++ic ) - { - compFrac[ic] = compDens[ic] * totalDensityInv; - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFrac_dCompDens[ic][jc] = -compFrac[ic] * totalDensityInv; - } - dCompFrac_dCompDens[ic][ic] += totalDensityInv; - } - - compFractionKernelOp( compFrac, dCompFrac_dCompDens ); - } - -protected: - - // inputs - - // Views on component densities - arrayView2d< real64 const, compflow::USD_COMP > m_compDens; - - // outputs - - // Views on component fraction - arrayView2d< real64, compflow::USD_COMP > m_compFrac; - arrayView3d< real64, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; - -}; - -/** - * @class GlobalComponentFractionKernelFactory - */ -class GlobalComponentFractionKernelFactory -{ -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] subRegion the element subregion - * @param[in] fluid the fluid model - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - ObjectManagerBase & subRegion ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - GlobalComponentFractionKernel< NUM_COMP > kernel( subRegion ); - GlobalComponentFractionKernel< NUM_COMP >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - -}; - -/******************************** PhaseVolumeFractionKernel ********************************/ - -/** - * @class PhaseVolumeFractionKernel - * @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 phase volume fractions - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseVolumeFractionKernel : public PropertyKernelBase< NUM_COMP > -{ -public: - - using Base = PropertyKernelBase< NUM_COMP >; - using Base::numComp; - - /// Compile time value for the number of phases - static constexpr integer numPhase = NUM_PHASE; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid ) - : Base(), - m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), - m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), - m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), - m_phaseFrac( fluid.phaseFraction() ), - m_dPhaseFrac( fluid.dPhaseFraction() ), - m_phaseDens( fluid.phaseDensity() ), - m_dPhaseDens( fluid.dPhaseDensity() ) - {} - - /** - * @brief Compute the phase volume fractions 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] phaseVolFractionKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - real64 compute( localIndex const ei, - FUNC && phaseVolFractionKernelOp = NoOpFunc{} ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac = m_phaseFrac[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; - arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - real64 work[numComp]{}; - - // compute total density from component partial densities - real64 totalDensity = 0.0; - real64 const dTotalDens_dCompDens = 1.0; - for( integer ic = 0; ic < numComp; ++ic ) - { - totalDensity += compDens[ic]; - } - - real64 maxDeltaPhaseVolFrac = 0.0; - - for( integer ip = 0; ip < numPhase; ++ip ) - { - - // set the saturation to zero if the phase is absent - bool const phaseExists = (phaseFrac[ip] > 0); - if( !phaseExists ) - { - phaseVolFrac[ip] = 0.; - for( integer jc = 0; jc < numComp+2; ++jc ) - { - dPhaseVolFrac[ip][jc] = 0.; - } - continue; - } - - // Expression for volume fractions: S_p = (nu_p / rho_p) * rho_t - real64 const phaseDensInv = 1.0 / phaseDens[ip]; - - // store old saturation to compute change later - real64 const satOld = phaseVolFrac[ip]; - - // compute saturation and derivatives except multiplying by the total density - phaseVolFrac[ip] = phaseFrac[ip] * phaseDensInv; - - dPhaseVolFrac[ip][Deriv::dP] = - (dPhaseFrac[ip][Deriv::dP] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP]) * phaseDensInv; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseVolFrac[ip][Deriv::dC+jc] = - (dPhaseFrac[ip][Deriv::dC+jc] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dC+jc]) * phaseDensInv; - } - - // apply chain rule to convert derivatives from global component fractions to densities - applyChainRuleInPlace( numComp, dCompFrac_dCompDens, dPhaseVolFrac[ip], work, Deriv::dC ); - - // call the lambda in the phase loop to allow the reuse of the phaseVolFrac and totalDensity - // possible use: assemble the derivatives wrt temperature - phaseVolFractionKernelOp( ip, phaseVolFrac[ip], phaseDensInv, totalDensity ); - - // now finalize the computation by multiplying by total density - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseVolFrac[ip][Deriv::dC+jc] *= totalDensity; - dPhaseVolFrac[ip][Deriv::dC+jc] += phaseVolFrac[ip] * dTotalDens_dCompDens; - } - - phaseVolFrac[ip] *= totalDensity; - dPhaseVolFrac[ip][Deriv::dP] *= totalDensity; - - real64 const deltaPhaseVolFrac = LvArray::math::abs( phaseVolFrac[ip] - satOld ); - if( maxDeltaPhaseVolFrac < deltaPhaseVolFrac ) - { - maxDeltaPhaseVolFrac = deltaPhaseVolFrac; - } - } - return maxDeltaPhaseVolFrac; - } - - /** - * @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 the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static real64 - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPhaseVolFrac( 0.0 ); - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - real64 const deltaPhaseVolFrac = kernelComponent.compute( ei ); - maxDeltaPhaseVolFrac.max( deltaPhaseVolFrac ); - } ); - return maxDeltaPhaseVolFrac.get(); - } - -protected: - - // outputs - - /// Views on phase volume fractions - arrayView2d< real64, compflow::USD_PHASE > m_phaseVolFrac; - arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseVolFrac; - - // inputs - - /// Views on component densities - arrayView2d< real64 const, compflow::USD_COMP > m_compDens; - arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; - - /// Views on phase fractions - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseFrac; - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseFrac; - - /// Views on phase densities - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseDens; - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseDens; - -}; - -/** - * @class PhaseVolumeFractionKernelFactory - */ -class PhaseVolumeFractionKernelFactory -{ -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 real64 - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid ) - { - real64 maxDeltaPhaseVolFrac = 0.0; - if( numPhase == 2 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - return maxDeltaPhaseVolFrac; - } -}; - - -/******************************** RelativePermeabilityUpdateKernel ********************************/ - -struct RelativePermeabilityUpdateKernel -{ - template< typename POLICY, typename RELPERM_WRAPPER > - static void - launch( localIndex const size, - RELPERM_WRAPPER const & relPermWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) - { - relPermWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } - - template< typename POLICY, typename RELPERM_WRAPPER > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - RELPERM_WRAPPER const & relPermWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - localIndex const k = targetSet[a]; - for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) - { - relPermWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } -}; - -/******************************** CapillaryPressureUpdateKernel ********************************/ - -struct CapillaryPressureUpdateKernel -{ - template< typename POLICY, typename CAPPRES_WRAPPER > - static void - launch( localIndex const size, - CAPPRES_WRAPPER const & capPresWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) - { - capPresWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } - - template< typename POLICY, typename CAPPRES_WRAPPER > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - CAPPRES_WRAPPER const & capPresWrapper, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - localIndex const k = targetSet[a]; - for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) - { - capPresWrapper.update( k, q, phaseVolFrac[k] ); - } - } ); - } -}; - -/******************************** 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, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< 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_porosity( solid.getPorosity() ), - m_dPoro_dPres( solid.getDporosity_dPressure() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), - m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), - m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), - m_phaseDens( fluid.phaseDensity() ), - m_dPhaseDens( fluid.dPhaseDensity() ), - m_phaseCompFrac( fluid.phaseCompFraction() ), - m_dPhaseCompFrac( fluid.dPhaseCompFraction() ), - m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), - m_compAmount_n( subRegion.getField< fields::flow::compAmount_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: - - // Pore volume information (used by both accumulation and volume balance) - - /// Pore volume at time n+1 - real64 poreVolume = 0.0; - - /// Derivative of pore volume with respect to pressure - real64 dPoreVolume_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]{}; - - /// 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 pore volume - stack.poreVolume = m_volume[ei] * m_porosity[ei][0]; - stack.dPoreVolume_dPres = m_volume[ei] * m_dPoro_dPres[ei][0]; - - // 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 - { - if( m_kernelFlags.isSet( ElementBasedAssemblyKernelFlags::SimpleAccumulation ) ) - { - // 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 compAmount = stack.poreVolume * m_compDens[ei][ic]; - real64 const compAmount_n = m_compAmount_n[ei][ic]; - - stack.localResidual[ic] += compAmount - compAmount_n; - - // Pavel: commented below is some experiment, needs to be re-tested - //real64 const compDens = (ic == 0 && m_compDens[ei][ic] < 1e-6) ? 1e-3 : m_compDens[ei][ic]; - real64 const dCompAmount_dP = stack.dPoreVolume_dPres * m_compDens[ei][ic]; - stack.localJacobian[ic][0] += dCompAmount_dP; - - real64 const dCompAmount_dC = stack.poreVolume; - stack.localJacobian[ic][ic + 1] += dCompAmount_dC; - } - } - else - { - using Deriv = constitutive::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 = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; - - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; - arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; - - // temporary work arrays - real64 dPhaseAmount_dC[numComp]{}; - real64 dPhaseCompFrac_dC[numComp]{}; - - // start with old time step values - for( integer ic = 0; ic < numComp; ++ic ) - { - stack.localResidual[ic] = -m_compAmount_n[ei][ic]; - } - - // sum contributions to component accumulation from each phase - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - real64 const phaseAmount = stack.poreVolume * phaseVolFrac[ip] * phaseDens[ip]; - - real64 const dPhaseAmount_dP = stack.dPoreVolume_dPres * phaseVolFrac[ip] * phaseDens[ip] - + stack.poreVolume * ( 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.poreVolume; - } - - // 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 dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] - + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dP]; - - stack.localResidual[ic] += phaseCompAmount; - 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, dPhaseAmount_dP, dPhaseAmount_dC ); - - } - } - } - - /** - * @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 = constitutive::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 - phaseVolFractionSumKernelOp( oneMinusPhaseVolFracSum ); - - // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) - stack.localResidual[numComp] = stack.poreVolume * oneMinusPhaseVolFracSum; - for( integer idof = 0; idof < numDof; ++idof ) - { - stack.localJacobian[numComp][idof] *= stack.poreVolume; - } - stack.localJacobian[numComp][0] += stack.dPoreVolume_dPres * oneMinusPhaseVolFracSum; - } - - /** - * @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( 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; - 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; - arrayView3d< real64 const, compflow::USD_PHASE_DC > const m_dPhaseVolFrac; - - /// Views on the phase densities - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens; - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const m_dPhaseDens; - - /// Views on the phase component fraction - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const m_phaseCompFrac; - arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > const m_dPhaseCompFrac; - - // View on component densities - arrayView2d< real64 const, compflow::USD_COMP > m_compDens; - - // View on component amount (mass/moles) from previous time step - arrayView2d< real64 const, compflow::USD_COMP > m_compAmount_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< 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[in] solid the solid model - * @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, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - integer const useSimpleAccumulation, - string const dofKey, - ElementSubRegionBase const & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - internal::kernelLaunchSelectorCompSwitch( numComps, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC()+1; - - BitFlags< ElementBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( ElementBasedAssemblyKernelFlags::TotalMassEquation ); - if( useSimpleAccumulation ) - kernelFlags.set( ElementBasedAssemblyKernelFlags::SimpleAccumulation ); - - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > - kernel( numPhases, rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs, kernelFlags ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - -}; - -/******************************** ScalingForSystemSolutionKernel ********************************/ - -/** - * @class ScalingAndCheckingSystemSolutionKernelBase - * @brief Define the kernel for scaling the solution and check its validity - */ -template< typename TYPE > -class ScalingAndCheckingSystemSolutionKernelBase -{ -public: - - /** - * @brief Create a new kernel instance - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] compDens the component density vector - * @param[in] pressureScalingFactor the pressure local scaling factor - * @param[in] compDensScalingFactor the component local scaling factor - */ - ScalingAndCheckingSystemSolutionKernelBase( 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 ) - : m_rankOffset( rankOffset ), - m_numComp( numComp ), - m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), - m_ghostRank( subRegion.ghostRank() ), - m_localSolution( localSolution ), - m_pressure( pressure ), // not passed with fields::flow to be able to reuse this for wells - m_compDens( compDens ), // same here - m_pressureScalingFactor( pressureScalingFactor ), - m_compDensScalingFactor( compDensScalingFactor ) - { } - - /** - * @struct StackVariables - * @brief Kernel variables located on the stack - */ - struct StackVariables - { - GEOS_HOST_DEVICE - StackVariables() - { } - - StackVariables( real64 _localMinVal ) - : - localMinVal( _localMinVal ) - { } - - /// Index of the local row corresponding to this element - localIndex localRow; - - /// The local value - TYPE localMinVal; - }; - - /** - * @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 - { - stack.localMinVal = 1; - - // set row index and degrees of freedom indices for this element - stack.localRow = m_dofNumber[ei] - m_rankOffset; - } - - /** - * @brief Getter for the ghost rank - * @param[in] i the looping index of the element/node/face - * @return the ghost rank of the element/node/face - */ - GEOS_HOST_DEVICE - integer ghostRank( localIndex const i ) const - { return m_ghostRank( i ); } - - /** - * @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 the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static TYPE - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, TYPE > minVal( 1 ); - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.ghostRank( ei ) >= 0 ) - { - return; - } - - StackVariables stack; - kernelComponent.setup( ei, stack ); - kernelComponent.compute( ei, stack ); - minVal.min( stack.localMinVal ); - } ); - - return minVal.get(); - } - -protected: - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// Number of components - real64 const m_numComp; - - /// View on the dof numbers - arrayView1d< globalIndex const > const m_dofNumber; - - /// View on the ghost ranks - arrayView1d< integer const > const m_ghostRank; - - /// View on the local residual - arrayView1d< real64 const > const m_localSolution; - - /// View on the primary variables - arrayView1d< real64 const > const m_pressure; - arrayView2d< real64 const, compflow::USD_COMP > const m_compDens; - - /// View on the scaling factors - arrayView1d< real64 > const m_pressureScalingFactor; - arrayView1d< real64 > const m_compDensScalingFactor; - -}; - -/** - * @class ScalingForSystemSolutionKernel - * @brief Define the kernel for scaling the Newton update - */ -class ScalingForSystemSolutionKernel : public ScalingAndCheckingSystemSolutionKernelBase< real64 > -{ -public: - - using Base = ScalingAndCheckingSystemSolutionKernelBase< real64 >; - using Base::m_rankOffset; - using Base::m_numComp; - using Base::m_dofNumber; - using Base::m_ghostRank; - using Base::m_localSolution; - using Base::m_pressure; - using Base::m_compDens; - using Base::m_pressureScalingFactor; - using Base::m_compDensScalingFactor; - - /** - * @brief Create a new kernel instance - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxAbsolutePresChange the max allowed absolute pressure change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] maxRelativeCompDensChange the max allowed comp density change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] compDens the component density vector - * @param[in] pressureScalingFactor the pressure local scaling factor - * @param[in] compDensScalingFactor the component density local scaling factor - */ - ScalingForSystemSolutionKernel( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxCompFracChange, - real64 const maxRelativeCompDensChange, - 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 ) - : Base( rankOffset, - numComp, - dofKey, - subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), - m_maxRelativePresChange( maxRelativePresChange ), - m_maxAbsolutePresChange( maxAbsolutePresChange ), - m_maxCompFracChange( maxCompFracChange ), - m_maxRelativeCompDensChange( maxRelativeCompDensChange ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables located on the stack - */ - struct StackVariables : public Base::StackVariables - { - GEOS_HOST_DEVICE - StackVariables() - { } - - StackVariables( real64 _localMinVal, - real64 _localMaxDeltaPres, - real64 _localMaxDeltaTemp, - real64 _localMaxDeltaCompDens, - real64 _localMinPresScalingFactor, - real64 _localMinTempScalingFactor, - real64 _localMinCompDensScalingFactor ) - : - Base::StackVariables( _localMinVal ), - localMaxDeltaPres( _localMaxDeltaPres ), - localMaxDeltaTemp( _localMaxDeltaTemp ), - localMaxDeltaCompDens( _localMaxDeltaCompDens ), - localMinPresScalingFactor( _localMinPresScalingFactor ), - localMinTempScalingFactor( _localMinTempScalingFactor ), - localMinCompDensScalingFactor( _localMinCompDensScalingFactor ) - { } - - real64 localMaxDeltaPres; - real64 localMaxDeltaTemp; - real64 localMaxDeltaCompDens; - - real64 localMinPresScalingFactor; - real64 localMinTempScalingFactor; - real64 localMinCompDensScalingFactor; - - }; - - /** - * @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 the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static StackVariables - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > globalScalingFactor( 1.0 ); - - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPres( 0.0 ); - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaTemp( 0.0 ); - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaCompDens( 0.0 ); - - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPresScalingFactor( 1.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTempScalingFactor( 1.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minCompDensScalingFactor( 1.0 ); - - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.ghostRank( ei ) >= 0 ) - { - return; - } - - StackVariables stack; - kernelComponent.setup( ei, stack ); - kernelComponent.compute( ei, stack ); - - globalScalingFactor.min( stack.localMinVal ); - - maxDeltaPres.max( stack.localMaxDeltaPres ); - maxDeltaTemp.max( stack.localMaxDeltaTemp ); - maxDeltaCompDens.max( stack.localMaxDeltaCompDens ); - - minPresScalingFactor.min( stack.localMinPresScalingFactor ); - minTempScalingFactor.min( stack.localMinTempScalingFactor ); - minCompDensScalingFactor.min( stack.localMinCompDensScalingFactor ); - } ); - - return StackVariables( globalScalingFactor.get(), - maxDeltaPres.get(), - maxDeltaTemp.get(), - maxDeltaCompDens.get(), - minPresScalingFactor.get(), - minTempScalingFactor.get(), - minCompDensScalingFactor.get() ); - } - - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - Base::setup( ei, stack ); - - stack.localMaxDeltaPres = 0.0; - stack.localMaxDeltaTemp = 0.0; - stack.localMaxDeltaCompDens = 0.0; - - stack.localMinPresScalingFactor = 1.0; - stack.localMinTempScalingFactor = 1.0; - stack.localMinCompDensScalingFactor = 1.0; - } - - /** - * @brief Compute the local value - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void compute( localIndex const ei, - StackVariables & stack ) const - { - computeScalingFactor( ei, stack ); - } - - /** - * @brief Compute the local value of the scaling factor - * @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] kernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeScalingFactor( localIndex const ei, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - real64 constexpr eps = minDensForDivision; - - // compute the change in pressure - real64 const pres = m_pressure[ei]; - real64 const absPresChange = LvArray::math::abs( m_localSolution[stack.localRow] ); - if( stack.localMaxDeltaPres < absPresChange ) - { - stack.localMaxDeltaPres = absPresChange; - } - - // compute pressure scaling factor - real64 presScalingFactor = 1.0; - // when enabled, absolute change scaling has a priority over relative change - if( m_maxAbsolutePresChange > 0.0 ) // maxAbsolutePresChange <= 0.0 means that absolute scaling is disabled - { - if( absPresChange > m_maxAbsolutePresChange ) - { - presScalingFactor = m_maxAbsolutePresChange / absPresChange; - } - } - else if( pres > eps ) - { - real64 const relativePresChange = absPresChange / pres; - if( relativePresChange > m_maxRelativePresChange ) - { - presScalingFactor = m_maxRelativePresChange / relativePresChange; - } - } - m_pressureScalingFactor[ei] = presScalingFactor; - if( stack.localMinVal > presScalingFactor ) - { - stack.localMinVal = presScalingFactor; - } - if( stack.localMinPresScalingFactor > presScalingFactor ) - { - stack.localMinPresScalingFactor = presScalingFactor; - } - - real64 prevTotalDens = 0; - for( integer ic = 0; ic < m_numComp; ++ic ) - { - prevTotalDens += m_compDens[ei][ic]; - } - - m_compDensScalingFactor[ei] = 1.0; - - // compute the change in component densities and component fractions - for( integer ic = 0; ic < m_numComp; ++ic ) - { - // compute scaling factor based on relative change in component densities - real64 const absCompDensChange = LvArray::math::abs( m_localSolution[stack.localRow + ic + 1] ); - if( stack.localMaxDeltaCompDens < absCompDensChange ) - { - stack.localMaxDeltaCompDens = absCompDensChange; - } - - // This actually checks the change in component fraction, using a lagged total density - // Indeed we can rewrite the following check as: - // | prevCompDens / prevTotalDens - newCompDens / prevTotalDens | > maxCompFracChange - // Note that the total density in the second term is lagged (i.e, we use prevTotalDens) - // because I found it more robust than using directly newTotalDens (which can vary also - // wildly when the compDens change is large) - real64 const maxAbsCompDensChange = m_maxCompFracChange * prevTotalDens; - if( absCompDensChange > maxAbsCompDensChange && absCompDensChange > eps ) - { - real64 const compScalingFactor = maxAbsCompDensChange / absCompDensChange; - m_compDensScalingFactor[ei] = LvArray::math::min( m_compDensScalingFactor[ei], compScalingFactor ); - if( stack.localMinVal > compScalingFactor ) - { - stack.localMinVal = compScalingFactor; - } - if( stack.localMinCompDensScalingFactor > compScalingFactor ) - { - stack.localMinCompDensScalingFactor = compScalingFactor; - } - } - - // switch from relative to absolute when value is < 1.0 - real64 const maxRelCompDensChange = m_maxRelativeCompDensChange * LvArray::math::max( m_compDens[ei][ic], 1.0 ); - if( absCompDensChange > maxRelCompDensChange && absCompDensChange > eps ) - { - real64 const compScalingFactor = maxRelCompDensChange / absCompDensChange; - m_compDensScalingFactor[ei] = LvArray::math::min( m_compDensScalingFactor[ei], compScalingFactor ); - if( stack.localMinVal > compScalingFactor ) - { - stack.localMinVal = compScalingFactor; - } - if( stack.localMinCompDensScalingFactor > compScalingFactor ) - { - stack.localMinCompDensScalingFactor = compScalingFactor; - } - } - } - - // compute the scaling factor for other vars, such as temperature - kernelOp(); - } - -protected: - - /// Max allowed changes in primary variables - real64 const m_maxRelativePresChange; - real64 const m_maxAbsolutePresChange; - real64 const m_maxCompFracChange; - real64 const m_maxRelativeCompDensChange; - -}; - -/** - * @class ScalingForSystemSolutionKernelFactory - */ -class ScalingForSystemSolutionKernelFactory -{ -public: - - /* - * @brief Create and launch the kernel computing the scaling factor - * @tparam POLICY the kernel policy - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxAbsolutePresChange the max allowed absolute pressure change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] maxRelativeCompDensChange the max allowed comp density change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @return the scaling factor - */ - template< typename POLICY > - static ScalingForSystemSolutionKernel::StackVariables - createAndLaunch( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxCompFracChange, - real64 const maxRelativeCompDensChange, - 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 ) - { - - ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, maxRelativeCompDensChange, rankOffset, - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); - return ScalingForSystemSolutionKernel::launch< POLICY >( subRegion.size(), kernel ); - } -}; - -/******************************** SolutionCheckKernel ********************************/ - -/** - * @class SolutionCheckKernel - * @brief Define the kernel for checking the updated solution - */ -class SolutionCheckKernel : public ScalingAndCheckingSystemSolutionKernelBase< integer > -{ -public: - - using Base = ScalingAndCheckingSystemSolutionKernelBase< integer >; - using Base::m_rankOffset; - using Base::m_numComp; - using Base::m_dofNumber; - using Base::m_ghostRank; - using Base::m_localSolution; - using Base::m_pressure; - using Base::m_compDens; - - /** - * @brief Create a new kernel instance - * @param[in] allowCompDensChopping flag to allow the component density chopping - * @param[in] scalingFactor the scaling factor - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] compDens the component density vector - */ - SolutionCheckKernel( integer const allowCompDensChopping, - 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 ) - : Base( rankOffset, - numComp, - dofKey, - subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), - m_allowCompDensChopping( allowCompDensChopping ), - m_allowNegativePressure( allowNegativePressure ), - m_scalingFactor( scalingFactor ), - m_scalingType( scalingType ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables located on the stack - */ - struct StackVariables : public Base::StackVariables - { - GEOS_HOST_DEVICE - StackVariables() - { } - - StackVariables( real64 _localMinVal, - real64 _localMinPres, - real64 _localMinDens, - real64 _localMinTotalDens, - integer _localNumNegPressures, - integer _localNumNegDens, - integer _localNumNegTotalDens ) - : - Base::StackVariables( _localMinVal ), - localMinPres( _localMinPres ), - localMinDens( _localMinDens ), - localMinTotalDens( _localMinTotalDens ), - localNumNegPressures( _localNumNegPressures ), - localNumNegDens( _localNumNegDens ), - localNumNegTotalDens( _localNumNegTotalDens ) - { } - - real64 localMinPres; - real64 localMinDens; - real64 localMinTotalDens; - - integer localNumNegPressures; - integer localNumNegDens; - integer localNumNegTotalDens; - - }; - - /** - * @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 the compute function - */ - template< typename POLICY, typename KERNEL_TYPE > - static StackVariables - launch( localIndex const numElems, - KERNEL_TYPE const & kernelComponent ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, integer > globalMinVal( 1 ); - - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minDens( 0.0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTotalDens( 0.0 ); - - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegPressures( 0 ); - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegDens( 0 ); - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegTotalDens( 0 ); - - forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( kernelComponent.ghostRank( ei ) >= 0 ) - { - return; - } - - StackVariables stack; - kernelComponent.setup( ei, stack ); - kernelComponent.compute( ei, stack ); - - globalMinVal.min( stack.localMinVal ); - - minPres.min( stack.localMinPres ); - minDens.min( stack.localMinDens ); - minTotalDens.min( stack.localMinTotalDens ); - - numNegPressures += stack.localNumNegPressures; - numNegDens += stack.localNumNegDens; - numNegTotalDens += stack.localNumNegTotalDens; - } ); - - return StackVariables( globalMinVal.get(), - minPres.get(), - minDens.get(), - minTotalDens.get(), - numNegPressures.get(), - numNegDens.get(), - numNegTotalDens.get() ); - } - - GEOS_HOST_DEVICE - void setup( localIndex const ei, - StackVariables & stack ) const - { - Base::setup( ei, stack ); - - stack.localMinPres = 0.0; - stack.localMinDens = 0.0; - stack.localMinTotalDens = 0.0; - - stack.localNumNegPressures = 0; - stack.localNumNegDens = 0; - stack.localNumNegTotalDens = 0; - } - - /** - * @brief Compute the local value - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void compute( localIndex const ei, - StackVariables & stack ) const - { - computeSolutionCheck( ei, stack ); - } - - /** - * @brief Compute the local value of the check - * @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] kernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeSolutionCheck( localIndex const ei, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - bool const localScaling = m_scalingType == CompositionalMultiphaseFVM::ScalingType::Local; - - real64 const newPres = m_pressure[ei] + (localScaling ? m_pressureScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow]; - if( newPres < 0 ) - { - if( !m_allowNegativePressure ) - { - stack.localMinVal = 0; - } - stack.localNumNegPressures += 1; - if( newPres < stack.localMinPres ) - stack.localMinPres = newPres; - } - - // if component density chopping is not allowed, the time step fails if a component density is negative - // otherwise, we just check that the total density is positive, and negative component densities - // will be chopped (i.e., set to zero) in ApplySystemSolution) - if( !m_allowCompDensChopping ) - { - for( integer ic = 0; ic < m_numComp; ++ic ) - { - real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; - if( newDens < 0 ) - { - stack.localMinVal = 0; - stack.localNumNegDens += 1; - if( newDens < stack.localMinDens ) - stack.localMinDens = newDens; - } - } - } - else - { - real64 totalDens = 0.0; - for( integer ic = 0; ic < m_numComp; ++ic ) - { - real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; - totalDens += ( newDens > 0.0 ) ? newDens : 0.0; - } - if( totalDens < 0 ) - { - stack.localMinVal = 0; - stack.localNumNegTotalDens += 1; - if( totalDens < stack.localMinTotalDens ) - stack.localMinTotalDens = totalDens; - } - } - - kernelOp(); - } - -protected: - - /// flag to allow the component density chopping - integer const m_allowCompDensChopping; - - /// flag to allow negative pressure values - integer const m_allowNegativePressure; - - /// scaling factor - real64 const m_scalingFactor; - - /// scaling type (global or local) - CompositionalMultiphaseFVM::ScalingType const m_scalingType; - -}; - -/** - * @class SolutionCheckKernelFactory - */ -class SolutionCheckKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] allowCompDensChopping flag to allow the component density chopping - * @param[in] scalingFactor the scaling factor - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static SolutionCheckKernel::StackVariables - createAndLaunch( integer const allowCompDensChopping, - 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 ) - { - - SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, - pressure, compDens, pressureScalingFactor, compDensScalingFactor, rankOffset, - numComp, dofKey, subRegion, localSolution ); - return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 > -{ -public: - - using Base = physicsSolverBaseKernels::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 numComponents, - ElementSubRegionBase const & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_numComponents( numComponents ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_totalDens_n( fluid.totalDensity_n() ) - {} - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - // this should never be zero if the simulation is set up correctly, but we never know - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); - - // step 1: mass residuals - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - } - - // step 2: volume residual - - real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; - if( valVol > stack.localValue[1] ) - { - stack.localValue[1] = valVol; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - // note: for the L2 norm, we bundle the volume and mass residuals/normalizers - - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - - // step 1: mass residuals - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; - stack.localNormalizer[0] += massNormalizer; - } - - // step 2: volume residual - - real64 const val = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the - // multiplication - stack.localValue[1] += val * val; - stack.localNormalizer[1] += massNormalizer; - } - - -protected: - - /// Number of fluid coponents - integer const m_numComponents; - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on porosity at the previous converged time step - arrayView2d< real64 const > const m_porosity_n; - - /// View on total mass/molar density at the previous converged time step - arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const m_totalDens_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @param[in] numComps the number of fluid components - * @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 element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( physicsSolverBaseKernels::NormType const normType, - integer const numComps, - globalIndex const rankOffset, - string const dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - real64 const minNormalizer, - real64 (& residualNorm)[2], - real64 (& residualNormalizer)[2] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, numComps, subRegion, fluid, solid, minNormalizer ); - if( normType == physicsSolverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - } - -}; - -/******************************** StatisticsKernel ********************************/ - -struct StatisticsKernel -{ - template< typename POLICY > - static void - saveDeltaPressure( localIndex const size, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & initPres, - arrayView1d< real64 > const & deltaPres ) - { - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - deltaPres[ei] = pres[ei] - initPres[ei]; - } ); - } - - template< typename POLICY > - static void - launch( localIndex const size, - integer const numComps, - integer const numPhases, - real64 const relpermThreshold, - arrayView1d< integer const > const & elemGhostRank, - arrayView1d< real64 const > const & volume, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & deltaPres, - arrayView1d< real64 const > const & temp, - arrayView1d< real64 const > const & refPorosity, - arrayView2d< real64 const > const & porosity, - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDensity, - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const & phaseCompFraction, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, - arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac, - arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseRelperm, - real64 & minPres, - real64 & avgPresNumerator, - real64 & maxPres, - real64 & minDeltaPres, - real64 & maxDeltaPres, - real64 & minTemp, - real64 & avgTempNumerator, - real64 & maxTemp, - real64 & totalUncompactedPoreVol, - arrayView1d< real64 > const & phaseDynamicPoreVol, - arrayView1d< real64 > const & phaseMass, - arrayView1d< real64 > const & trappedPhaseMass, - arrayView1d< real64 > const & immobilePhaseMass, - arrayView2d< real64 > const & dissolvedComponentMass ) - { - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); - - // For this arrays phaseDynamicPoreVol, phaseMass, dissolvedComponentMass, - // using an array of ReduceSum leads to a formal parameter overflow in CUDA. - // As a workaround, we use a slice with RAJA::atomicAdd instead - - forAll< parallelDevicePolicy<> >( size, [numComps, - numPhases, - relpermThreshold, - elemGhostRank, - volume, - refPorosity, - porosity, - pres, - deltaPres, - temp, - phaseDensity, - phaseVolFrac, - phaseTrappedVolFrac, - phaseRelperm, - phaseCompFraction, - subRegionMinPres, - subRegionAvgPresNumerator, - subRegionMaxPres, - subRegionMinDeltaPres, - subRegionMaxDeltaPres, - subRegionMinTemp, - subRegionAvgTempNumerator, - subRegionMaxTemp, - subRegionTotalUncompactedPoreVol, - phaseDynamicPoreVol, - phaseMass, - trappedPhaseMass, - immobilePhaseMass, - dissolvedComponentMass] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( elemGhostRank[ei] >= 0 ) - { - return; - } - - // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages - real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; - real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; - - subRegionMinPres.min( pres[ei] ); - subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; - subRegionMaxPres.max( pres[ei] ); - - subRegionMaxDeltaPres.max( deltaPres[ei] ); - subRegionMinDeltaPres.min( deltaPres[ei] ); - - subRegionMinTemp.min( temp[ei] ); - subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; - subRegionMaxTemp.max( temp[ei] ); - subRegionTotalUncompactedPoreVol += uncompactedPoreVol; - for( integer ip = 0; ip < numPhases; ++ip ) - { - real64 const elemPhaseVolume = dynamicPoreVol * phaseVolFrac[ei][ip]; - real64 const elemPhaseMass = phaseDensity[ei][0][ip] * elemPhaseVolume; - real64 const elemTrappedPhaseMass = phaseDensity[ei][0][ip] * dynamicPoreVol * phaseTrappedVolFrac[ei][0][ip]; - // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) - RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseDynamicPoreVol[ip], elemPhaseVolume ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseMass[ip], elemPhaseMass ); - RAJA::atomicAdd( parallelDeviceAtomic{}, &trappedPhaseMass[ip], elemTrappedPhaseMass ); - if( phaseRelperm[ei][0][ip] < relpermThreshold ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &immobilePhaseMass[ip], elemPhaseMass ); - } - for( integer ic = 0; ic < numComps; ++ic ) - { - // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) - RAJA::atomicAdd( parallelDeviceAtomic{}, &dissolvedComponentMass[ip][ic], phaseCompFraction[ei][0][ip][ic] * elemPhaseMass ); - } - } - - } ); - - minPres = subRegionMinPres.get(); - avgPresNumerator = subRegionAvgPresNumerator.get(); - maxPres = subRegionMaxPres.get(); - minDeltaPres = subRegionMinDeltaPres.get(); - maxDeltaPres = subRegionMaxDeltaPres.get(); - minTemp = subRegionMinTemp.get(); - avgTempNumerator = subRegionAvgTempNumerator.get(); - maxTemp = subRegionMaxTemp.get(); - totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); - - // dummy loop to bring data back to the CPU - forAll< serialPolicy >( 1, [phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass] ( localIndex const ) - { - GEOS_UNUSED_VAR( phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass ); - } ); - } -}; - -/******************************** HydrostaticPressureKernel ********************************/ - -struct HydrostaticPressureKernel -{ - - // TODO: this type of constants should be centralized somewhere or provided by fluid model - static real64 constexpr MIN_FOR_PHASE_PRESENCE = 1e-12; - - enum class ReturnType : integer - { - FAILED_TO_CONVERGE = 0, - DETECTED_MULTIPHASE_FLOW = 1, - SUCCESS = 2 - }; - - template< typename FLUID_WRAPPER > - static ReturnType - computeHydrostaticPressure( integer const numComps, - integer const numPhases, - integer const ipInit, - integer const maxNumEquilIterations, - real64 const & equilTolerance, - real64 const (&gravVector)[ 3 ], - FLUID_WRAPPER fluidWrapper, - arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, - TableFunction::KernelWrapper tempTableWrapper, - real64 const & refElevation, - real64 const & refPres, - arraySlice1d< real64 const > const & refPhaseMassDens, - real64 const & newElevation, - real64 & newPres, - arraySlice1d< real64 > const & newPhaseMassDens ) - { - // fluid properties at this elevation - StackArray< real64, 2, constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, compflow::LAYOUT_COMP > compFrac( 1, numComps ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseFrac( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseDens( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseMassDens( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseVisc( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseEnthalpy( 1, 1, numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseInternalEnergy( 1, 1, numPhases ); - StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES *constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, - constitutive::multifluid::LAYOUT_PHASE_COMP > phaseCompFrac( 1, 1, numPhases, numComps ); - real64 totalDens = 0.0; - - bool isSinglePhaseFlow = true; - - // Step 1: compute the hydrostatic pressure at the current elevation - - real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); - real64 const temp = tempTableWrapper.compute( &newElevation ); - for( integer ic = 0; ic < numComps; ++ic ) - { - compFrac[0][ic] = compFracTableWrappers[ic].compute( &newElevation ); - } - - // Step 2: guess the pressure with the refPhaseMassDensity - - real64 pres0 = refPres - refPhaseMassDens[ipInit] * gravCoef; - real64 pres1 = 0.0; - - // Step 3: compute the mass density at this elevation using the guess, and update pressure - - constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, - pres0, - temp, - compFrac[0], - phaseFrac[0][0], - phaseDens[0][0], - phaseMassDens[0][0], - phaseVisc[0][0], - phaseEnthalpy[0][0], - phaseInternalEnergy[0][0], - phaseCompFrac[0][0], - totalDens ); - pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; - - // Step 4: fixed-point iteration until convergence - - bool equilHasConverged = false; - for( integer eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) - { - - // check convergence - equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); - pres0 = pres1; - - // if converged, check number of phases and move on - if( equilHasConverged ) - { - // make sure that the fluid is single-phase, other we have to issue a warning (for now) - // if only one phase is mobile, we are in good shape (unfortunately it is hard to access relperm from here) - localIndex numberOfPhases = 0; - for( integer ip = 0; ip < numPhases; ++ip ) - { - if( phaseFrac[0][0][ip] > MIN_FOR_PHASE_PRESENCE ) - { - numberOfPhases++; - } - } - if( numberOfPhases > 1 ) - { - isSinglePhaseFlow = false; - } - - break; - } - - // compute the mass density at this elevation using the previous pressure, and compute the new pressure - constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, - pres0, - temp, - compFrac[0], - phaseFrac[0][0], - phaseDens[0][0], - phaseMassDens[0][0], - phaseVisc[0][0], - phaseEnthalpy[0][0], - phaseInternalEnergy[0][0], - phaseCompFrac[0][0], - totalDens ); - pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; - } - - // Step 5: save the hydrostatic pressure and the corresponding density - - newPres = pres1; - for( integer ip = 0; ip < numPhases; ++ip ) - { - newPhaseMassDens[ip] = phaseMassDens[0][0][ip]; - } - - if( !equilHasConverged ) - { - return ReturnType::FAILED_TO_CONVERGE; - } - else if( !isSinglePhaseFlow ) - { - return ReturnType::DETECTED_MULTIPHASE_FLOW; - } - else - { - return ReturnType::SUCCESS; - } - } - - template< typename FLUID_WRAPPER > - static ReturnType - launch( localIndex const size, - integer const numComps, - integer const numPhases, - integer const ipInit, - integer const maxNumEquilIterations, - real64 const equilTolerance, - real64 const (&gravVector)[ 3 ], - real64 const & minElevation, - real64 const & elevationIncrement, - real64 const & datumElevation, - real64 const & datumPres, - FLUID_WRAPPER fluidWrapper, - arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, - TableFunction::KernelWrapper tempTableWrapper, - arrayView1d< arrayView1d< real64 > const > elevationValues, - arrayView1d< real64 > pressureValues ) - { - - ReturnType returnVal = ReturnType::SUCCESS; - - // Step 1: compute the phase mass densities at datum - - // datum fluid properties - array2d< real64, compflow::LAYOUT_COMP > datumCompFrac( 1, numComps ); - array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseFrac( 1, 1, numPhases ); - array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseDens( 1, 1, numPhases ); - array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseMassDens( 1, 1, numPhases ); - array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseVisc( 1, 1, numPhases ); - array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseEnthalpy( 1, 1, numPhases ); - array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseInternalEnergy( 1, 1, numPhases ); - array4d< real64, constitutive::multifluid::LAYOUT_PHASE_COMP > datumPhaseCompFrac( 1, 1, numPhases, numComps ); - real64 datumTotalDens = 0.0; - - real64 const datumTemp = tempTableWrapper.compute( &datumElevation ); - for( integer ic = 0; ic < numComps; ++ic ) - { - datumCompFrac[0][ic] = compFracTableWrappers[ic].compute( &datumElevation ); - } - constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, - datumPres, - datumTemp, - datumCompFrac[0], - datumPhaseFrac[0][0], - datumPhaseDens[0][0], - datumPhaseMassDens[0][0], - datumPhaseVisc[0][0], - datumPhaseEnthalpy[0][0], - datumPhaseInternalEnergy[0][0], - datumPhaseCompFrac[0][0], - datumTotalDens ); - - // Step 2: find the closest elevation to datumElevation - - forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) - { - real64 const elevation = minElevation + i * elevationIncrement; - elevationValues[0][i] = elevation; - } ); - integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), - elevationValues[0].size(), - datumElevation ); - - // Step 3: compute the mass density and pressure at the reference elevation - - array2d< real64 > phaseMassDens( pressureValues.size(), numPhases ); - // temporary array without permutation to compile on Lassen - array1d< real64 > datumPhaseMassDensTmp( numPhases ); - for( integer ip = 0; ip < numPhases; ++ip ) - { - datumPhaseMassDensTmp[ip] = datumPhaseMassDens[0][0][ip]; - } - - ReturnType const refReturnVal = - computeHydrostaticPressure( numComps, - numPhases, - ipInit, - maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - compFracTableWrappers, - tempTableWrapper, - datumElevation, - datumPres, - datumPhaseMassDensTmp, - elevationValues[0][iRef], - pressureValues[iRef], - phaseMassDens[iRef] ); - if( refReturnVal == ReturnType::FAILED_TO_CONVERGE ) - { - return ReturnType::FAILED_TO_CONVERGE; - } - else if( refReturnVal == ReturnType::DETECTED_MULTIPHASE_FLOW ) - { - returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; - } - - // Step 4: for each elevation above the reference elevation, compute the pressure - - localIndex const numEntriesAboveRef = size - iRef - 1; - forAll< serialPolicy >( numEntriesAboveRef, [=, &returnVal] ( localIndex const i ) - { - ReturnType const returnValAboveRef = - computeHydrostaticPressure( numComps, - numPhases, - ipInit, - maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - compFracTableWrappers, - tempTableWrapper, - elevationValues[0][iRef+i], - pressureValues[iRef+i], - phaseMassDens[iRef+i], - elevationValues[0][iRef+i+1], - pressureValues[iRef+i+1], - phaseMassDens[iRef+i+1] ); - if( returnValAboveRef == ReturnType::FAILED_TO_CONVERGE ) - { - returnVal = ReturnType::FAILED_TO_CONVERGE; - } - else if( ( returnValAboveRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && - ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) - { - returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; - } - - } ); - - // Step 5: for each elevation below the reference elevation, compute the pressure - - localIndex const numEntriesBelowRef = iRef; - forAll< serialPolicy >( numEntriesBelowRef, [=, &returnVal] ( localIndex const i ) - { - ReturnType const returnValBelowRef = - computeHydrostaticPressure( numComps, - numPhases, - ipInit, - maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - compFracTableWrappers, - tempTableWrapper, - elevationValues[0][iRef-i], - pressureValues[iRef-i], - phaseMassDens[iRef-i], - elevationValues[0][iRef-i-1], - pressureValues[iRef-i-1], - phaseMassDens[iRef-i-1] ); - if( returnValBelowRef == ReturnType::FAILED_TO_CONVERGE ) - { - returnVal = ReturnType::FAILED_TO_CONVERGE; - } - else if( ( returnValBelowRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && - ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) - { - returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; - } - - } ); - - return returnVal; - } - -}; - - -/******************************** Kernel launch machinery ********************************/ - - -template< typename KERNELWRAPPER, typename ... ARGS > -void KernelLaunchSelectorCompTherm( integer const numComp, bool const isThermal, ARGS && ... args ) -{ - geos::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 ) -{ - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - KERNELWRAPPER::template launch< NC() >( std::forward< ARGS >( args )... ); - } ); -} - -template< typename KERNELWRAPPER, typename ... ARGS > -void KernelLaunchSelector2( integer const numComp, integer const numPhase, 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( numPhase == 2 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - KERNELWRAPPER::template launch< NC(), 2 >( std::forward< ARGS >( args ) ... ); - } ); - } - else if( numPhase == 3 ) - { - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - KERNELWRAPPER::template launch< NC(), 3 >( std::forward< ARGS >( args ) ... ); - } ); - } - else - { - GEOS_ERROR( "Unsupported number of phases: " << numPhase ); - } -} - -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 - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index 4332a3caca9..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp +++ /dev/null @@ -1,2388 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file IsothermalCompositionalMultiphaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP - -#include "codingUtilities/Utilities.hpp" -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/capillaryPressure/CapillaryPressureFields.hpp" -#include "constitutive/capillaryPressure/CapillaryPressureBase.hpp" -#include "constitutive/diffusion/DiffusionFields.hpp" -#include "constitutive/diffusion/DiffusionBase.hpp" -#include "constitutive/dispersion/DispersionFields.hpp" -#include "constitutive/dispersion/DispersionBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" -#include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" -#include "constitutive/permeability/PermeabilityFields.hpp" -#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" -#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" -#include "constitutive/solid/porosity/PorosityBase.hpp" -#include "constitutive/solid/porosity/PorosityFields.hpp" -#include "fieldSpecification/AquiferBoundaryCondition.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" -#include "finiteVolume/BoundaryStencil.hpp" -#include "mesh/ElementRegionManager.hpp" -#include "mesh/utilities/MeshMapUtilities.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" -#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp" - -namespace geos -{ - -namespace isothermalCompositionalMultiphaseFVMKernels -{ - -enum class FaceBasedAssemblyKernelFlags -{ - /// Flag to specify whether capillary pressure is used or not - CapPressure = 1 << 0, // 1 - /// Flag indicating whether total mass equation is formed or not - TotalMassEquation = 1 << 1, // 2 - /// Flag indicating whether C1-PPU is used or not - C1PPU = 1 << 2, // 4 - /// Flag indicating whether IHU is used or not - IHU = 1 << 3 // 8 - /// Add more flags like that if needed: - // Flag5 = 1 << 4, // 16 - // Flag6 = 1 << 5, // 32 - // Flag7 = 1 << 6, // 64 - // Flag8 = 1 << 7 //128 -}; - -/******************************** PhaseMobilityKernel ********************************/ - -/** - * @class PhaseMobilityKernel - * @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 phase mobilities - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseMobilityKernel : public isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP > -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP >; - using Base::numComp; - - /// Compile time value for the number of phases - static constexpr integer numPhase = NUM_PHASE; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] relperm the relperm model - */ - PhaseMobilityKernel( ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::RelativePermeabilityBase const & relperm ) - : Base(), - m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), - m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), - m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), - m_phaseDens( fluid.phaseDensity() ), - m_dPhaseDens( fluid.dPhaseDensity() ), - m_phaseVisc( fluid.phaseViscosity() ), - m_dPhaseVisc( fluid.dPhaseViscosity() ), - m_phaseRelPerm( relperm.phaseRelPerm() ), - m_dPhaseRelPerm_dPhaseVolFrac( relperm.dPhaseRelPerm_dPhaseVolFraction() ), - m_phaseMob( subRegion.getField< fields::flow::phaseMobility >() ), - m_dPhaseMob( subRegion.getField< fields::flow::dPhaseMobility >() ) - {} - - /** - * @brief Compute the phase mobilities 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] phaseMobilityKernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void compute( localIndex const ei, - FUNC && phaseMobilityKernelOp = NoOpFunc{} ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; - arraySlice1d< real64 const, constitutive::relperm::USD_RELPERM - 2 > const phaseRelPerm = m_phaseRelPerm[ei][0]; - arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseMob = m_phaseMob[ei]; - arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseMob = m_dPhaseMob[ei]; - - real64 dRelPerm_dC[numComp]{}; - real64 dDens_dC[numComp]{}; - real64 dVisc_dC[numComp]{}; - - for( integer ip = 0; ip < numPhase; ++ip ) - { - - // compute the phase mobility only if the phase is present - bool const phaseExists = (phaseVolFrac[ip] > 0); - if( !phaseExists ) - { - phaseMob[ip] = 0.0; - for( integer jc = 0; jc < numComp + 2; ++jc ) - { - dPhaseMob[ip][jc] = 0.0; - } - continue; - } - - real64 const density = phaseDens[ip]; - real64 const dDens_dP = dPhaseDens[ip][Deriv::dP]; - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dDens_dC, Deriv::dC ); - - real64 const viscosity = phaseVisc[ip]; - real64 const dVisc_dP = dPhaseVisc[ip][Deriv::dP]; - applyChainRule( numComp, dCompFrac_dCompDens, dPhaseVisc[ip], dVisc_dC, Deriv::dC ); - - real64 const relPerm = phaseRelPerm[ip]; - real64 dRelPerm_dP = 0.0; - for( integer ic = 0; ic < numComp; ++ic ) - { - dRelPerm_dC[ic] = 0.0; - } - - for( integer jp = 0; jp < numPhase; ++jp ) - { - real64 const dRelPerm_dS = dPhaseRelPerm_dPhaseVolFrac[ip][jp]; - dRelPerm_dP += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dP]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dRelPerm_dC[jc] += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dC+jc]; - } - } - - real64 const mobility = relPerm * density / viscosity; - - phaseMob[ip] = mobility; - dPhaseMob[ip][Deriv::dP] = dRelPerm_dP * density / viscosity - + mobility * (dDens_dP / density - dVisc_dP / viscosity); - - // compositional derivatives - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseMob[ip][Deriv::dC+jc] = dRelPerm_dC[jc] * density / viscosity - + mobility * (dDens_dC[jc] / density - dVisc_dC[jc] / viscosity); - } - - // call the lambda in the phase loop to allow the reuse of the relperm, density, viscosity, and mobility - // possible use: assemble the derivatives wrt temperature - phaseMobilityKernelOp( ip, phaseMob[ip], dPhaseMob[ip] ); - } - } - -protected: - - // inputs - - /// Views on the phase volume fractions - arrayView2d< real64 const, compflow::USD_PHASE > m_phaseVolFrac; - arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; - arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; - - /// Views on the phase densities - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseDens; - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseDens; - - /// Views on the phase viscosities - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseVisc; - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseVisc; - - /// Views on the phase relative permeabilities - arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > m_phaseRelPerm; - arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; - - // outputs - - /// Views on the phase mobilities - arrayView2d< real64, compflow::USD_PHASE > m_phaseMob; - arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseMob; - -}; - -/** - * @class PhaseMobilityKernelFactory - */ -class PhaseMobilityKernelFactory -{ -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 - * @param[in] relperm the relperm model - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::RelativePermeabilityBase const & relperm ) - { - if( numPhase == 2 ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - } -}; - - -/******************************** FaceBasedAssemblyKernel ********************************/ - -/** - * @brief Base class for FaceBasedAssemblyKernel that holds all data not dependent - * on template parameters (like stencil type and number of components/dofs). - */ -class FaceBasedAssemblyKernelBase -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; - - using CompFlowAccessors = - StencilAccessors< fields::ghostRank, - fields::flow::gravityCoefficient, - fields::flow::pressure, - fields::flow::dGlobalCompFraction_dGlobalCompDensity, - fields::flow::phaseVolumeFraction, - fields::flow::dPhaseVolumeFraction, - fields::flow::phaseMobility, - fields::flow::dPhaseMobility >; - using MultiFluidAccessors = - StencilMaterialAccessors< constitutive::MultiFluidBase, - fields::multifluid::phaseDensity, - fields::multifluid::dPhaseDensity, - fields::multifluid::phaseMassDensity, - fields::multifluid::dPhaseMassDensity, - fields::multifluid::phaseCompFraction, - fields::multifluid::dPhaseCompFraction >; - - using CapPressureAccessors = - StencilMaterialAccessors< constitutive::CapillaryPressureBase, - fields::cappres::phaseCapPressure, - fields::cappres::dPhaseCapPressure_dPhaseVolFraction >; - - using PermeabilityAccessors = - StencilMaterialAccessors< constitutive::PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure >; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofNumberAccessor accessor for the dof numbers - * @param[in] compFlowAccessors accessor for wrappers registered by the solver - * @param[in] multiFluidAccessors accessor for wrappers registered by the multifluid model - * @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 all together - */ - FaceBasedAssemblyKernelBase( integer const numPhases, - globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ); - -protected: - - /// Number of fluid phases - integer const m_numPhases; - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// Time step size - real64 const m_dt; - - /// Views on dof numbers - ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; - - /// Views on ghost rank numbers and gravity coefficients - ElementViewConst< arrayView1d< integer const > > const m_ghostRank; - ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; - - // Primary and secondary variables - - /// Views on pressure - ElementViewConst< arrayView1d< real64 const > > const m_pres; - - /// Views on phase volume fractions - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseVolFrac; - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseVolFrac; - - /// Views on derivatives of comp fractions - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dCompFrac_dCompDens; - - /// Views on phase component fractions - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_phaseCompFrac; - ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const m_dPhaseCompFrac; - - // Residual and jacobian - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - - BitFlags< FaceBasedAssemblyKernelFlags > const m_kernelFlags; -}; - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase -{ -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 (all of them, except the volume balance equation) - static constexpr integer numEqn = NUM_DOF-1; - - /// Maximum number of elements at the face - static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; - - /// Maximum number of connections at the face - static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; - - /// Maximum number of points in the stencil - static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; - - /// Number of flux support points (hard-coded for TFPA) - static constexpr integer numFluxSupportPoints = 2; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @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( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : FaceBasedAssemblyKernelBase( numPhases, - rankOffset, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), - m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), - m_phaseMob( compFlowAccessors.get( fields::flow::phaseMobility {} ) ), - m_dPhaseMob( compFlowAccessors.get( fields::flow::dPhaseMobility {} ) ), - m_phaseMassDens( multiFluidAccessors.get( fields::multifluid::phaseMassDensity {} ) ), - m_dPhaseMassDens( multiFluidAccessors.get( fields::multifluid::dPhaseMassDensity {} ) ), - m_phaseCapPressure( capPressureAccessors.get( fields::cappres::phaseCapPressure {} ) ), - m_dPhaseCapPressure_dPhaseVolFrac( capPressureAccessors.get( fields::cappres::dPhaseCapPressure_dPhaseVolFraction {} ) ), - m_stencilWrapper( stencilWrapper ), - m_seri( stencilWrapper.getElementRegionIndices() ), - m_sesri( stencilWrapper.getElementSubRegionIndices() ), - m_sei( stencilWrapper.getElementIndices() ) - { } - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - 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, localIndex numElems ) - : stencilSize( size ), - numConnectedElems( numElems ), - dofColIndices( size * numDof ), - localFlux( numElems * numEqn ), - localFluxJacobian( numElems * numEqn, size * numDof ) - {} - - // Stencil information - - /// Stencil size for a given connection - localIndex const stencilSize; - /// Number of elements connected at a given connection - localIndex const numConnectedElems; - - // Transmissibility and derivatives - - /// Transmissibility - real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; - /// Derivatives of transmissibility with respect to pressure - real64 dTrans_dPres[maxNumConns][numFluxSupportPoints]{}; - - // 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 equations except volume balance) - stackArray1d< real64, maxNumElems * numEqn > localFlux; - /// Storage for the face local Jacobian matrix - stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; - }; - - - /** - * @brief Getter for the stencil size at this connection - * @param[in] iconn the connection index - * @return the size of the stencil at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex stencilSize( localIndex const iconn ) const { return m_sei[iconn].size(); } - - /** - * @brief Getter for the number of elements at this connection - * @param[in] iconn the connection index - * @return the number of elements at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex numPointsInFlux( localIndex const iconn ) const { return m_stencilWrapper.numPointsInFlux( iconn ); } - - - /** - * @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 - { - // set degrees of freedom indices for this face - for( integer i = 0; i < stack.stencilSize; ++i ) - { - globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[i * numDof + jdof] = offset + 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] iconn the connection 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 iconn, - StackVariables & stack, - FUNC && compFluxKernelOp = NoOpFunc{} ) const - { - - // first, compute the transmissibilities at this face - m_stencilWrapper.computeWeights( iconn, - m_permeability, - m_dPerm_dPres, - stack.transmissibility, - stack.dTrans_dPres ); - - - localIndex k[numFluxSupportPoints]; - localIndex connectionIndex = 0; - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - /// cell indices - localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // clear working arrays - real64 compFlux[numComp]{}; - real64 dCompFlux_dP[numFluxSupportPoints][numComp]{}; - real64 dCompFlux_dC[numFluxSupportPoints][numComp][numComp]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - real64 const dTrans_dPres[numFluxSupportPoints] = { stack.dTrans_dPres[connectionIndex][0], - stack.dTrans_dPres[connectionIndex][1] }; - - //***** calculation of flux ***** - // loop over phases, compute and upwind phase flux and sum contributions to each component's flux - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - // create local work arrays - real64 potGrad = 0.0; - real64 phaseFlux = 0.0; - real64 dPhaseFlux_dP[numFluxSupportPoints]{}; - real64 dPhaseFlux_dC[numFluxSupportPoints][numComp]{}; - - localIndex k_up = -1; - - if( m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::C1PPU ) ) - { - isothermalCompositionalMultiphaseFVMKernelUtilities::C1PPUPhaseFlux::compute< numComp, numFluxSupportPoints > - ( m_numPhases, - ip, - m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::CapPressure ), - seri, sesri, sei, - trans, - dTrans_dPres, - m_pres, - m_gravCoef, - m_phaseMob, m_dPhaseMob, - m_phaseVolFrac, m_dPhaseVolFrac, - m_phaseCompFrac, m_dPhaseCompFrac, - m_dCompFrac_dCompDens, - m_phaseMassDens, m_dPhaseMassDens, - m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, - k_up, - potGrad, - phaseFlux, - dPhaseFlux_dP, - dPhaseFlux_dC, - compFlux, - dCompFlux_dP, - dCompFlux_dC ); - } - else if( m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::IHU ) ) - { - isothermalCompositionalMultiphaseFVMKernelUtilities::IHUPhaseFlux::compute< numComp, numFluxSupportPoints > - ( m_numPhases, - ip, - m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::CapPressure ), - seri, sesri, sei, - trans, - dTrans_dPres, - m_pres, - m_gravCoef, - m_phaseMob, m_dPhaseMob, - m_phaseVolFrac, m_dPhaseVolFrac, - m_phaseCompFrac, m_dPhaseCompFrac, - m_dCompFrac_dCompDens, - m_phaseMassDens, m_dPhaseMassDens, - m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, - k_up, - potGrad, - phaseFlux, - dPhaseFlux_dP, - dPhaseFlux_dC, - compFlux, - dCompFlux_dP, - dCompFlux_dC ); - } - else - { - isothermalCompositionalMultiphaseFVMKernelUtilities::PPUPhaseFlux::compute< numComp, numFluxSupportPoints > - ( m_numPhases, - ip, - m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::CapPressure ), - seri, sesri, sei, - trans, - dTrans_dPres, - m_pres, - m_gravCoef, - m_phaseMob, m_dPhaseMob, - m_phaseVolFrac, m_dPhaseVolFrac, - m_phaseCompFrac, m_dPhaseCompFrac, - m_dCompFrac_dCompDens, - m_phaseMassDens, m_dPhaseMassDens, - m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, - k_up, - potGrad, - phaseFlux, - dPhaseFlux_dP, - dPhaseFlux_dC, - compFlux, - dCompFlux_dP, - dCompFlux_dC ); - } - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - compFluxKernelOp( ip, k, seri, sesri, sei, connectionIndex, - k_up, seri[k_up], sesri[k_up], sei[k_up], potGrad, - phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); - - } // loop over phases - - /// populate local flux vector and derivatives - for( integer ic = 0; ic < numComp; ++ic ) - { - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - stack.localFlux[eqIndex0] += m_dt * compFlux[ic]; - stack.localFlux[eqIndex1] -= m_dt * compFlux[ic]; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dCompFlux_dP[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dCompFlux_dP[ke][ic]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dCompFlux_dC[ke][ic][jc]; - stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dCompFlux_dC[ke][ic][jc]; - } - } - } - connectionIndex++; - } // loop over k[1] - } // loop over k[0] - - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = NoOpFunc{} ) const - { - using namespace compositionalMultiphaseUtilities; - - if( m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::TotalMassEquation ) ) - { - // Apply equation/variable change transformation(s) - stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof * stack.stencilSize, stack.numConnectedElems, - stack.localFluxJacobian, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, - stack.localFlux ); - } - - // add contribution to residual and jacobian into: - // - the component mass balance equations (i = 0 to i = numComp-1) - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - for( integer i = 0; i < stack.numConnectedElems; ++i ) - { - if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); - - for( integer ic = 0; ic < numComp; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], - stack.localFlux[i * numEqn + ic] ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + ic, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), - stack.stencilSize * numDof ); - } - - // call the lambda to assemble additional terms, such as thermal terms - assemblyKernelOp( i, localRow ); - } - } - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numConnections the number of connections - * @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 numConnections, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - kernelComponent.numPointsInFlux( iconn ) ); - - kernelComponent.setup( iconn, stack ); - kernelComponent.computeFlux( iconn, stack ); - kernelComponent.complete( iconn, stack ); - } ); - } - -protected: - - /// Views on permeability - ElementViewConst< arrayView3d< real64 const > > const m_permeability; - ElementViewConst< arrayView3d< real64 const > > const m_dPerm_dPres; - - /// Views on phase mobilities - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseMob; - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseMob; - - /// Views on phase mass densities - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseMassDens; - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseMassDens; - - /// Views on phase capillary pressure - ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const m_phaseCapPressure; - ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const m_dPhaseCapPressure_dPhaseVolFrac; - - // Stencil information - - /// Reference to the stencil wrapper - STENCILWRAPPER const m_stencilWrapper; - - /// Connection to element maps - typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; - -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @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 string to get the element degrees of freedom numbers - * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasCapPressure, - integer const useTotalMassEquation, - UpwindingParameters upwindingParams, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - 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() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags; - if( hasCapPressure ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::CapPressure ); - if( useTotalMassEquation ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::TotalMassEquation ); - if( upwindingParams.upwindingScheme == UpwindingScheme::C1PPU && - isothermalCompositionalMultiphaseFVMKernelUtilities::epsC1PPU > 0 ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::C1PPU ); - else if( upwindingParams.upwindingScheme == UpwindingScheme::IHU ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::IHU ); - - - using kernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, - compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - -/******************************** DiffusionDispersionFaceBasedAssemblyKernel ********************************/ - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class DiffusionDispersionFaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase -{ -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 (all of them, except the volume balance equation) - static constexpr integer numEqn = NUM_DOF-1; - - /// Maximum number of elements at the face - static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; - - /// Maximum number of connections at the face - static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; - - /// Maximum number of points in the stencil - static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; - - /// Number of flux support points (hard-coded for TFPA) - static constexpr integer numFluxSupportPoints = 2; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using AbstractBase::m_dPhaseVolFrac; - using AbstractBase::m_kernelFlags; - - using DiffusionAccessors = - StencilMaterialAccessors< constitutive::DiffusionBase, - fields::diffusion::diffusivity, - fields::diffusion::dDiffusivity_dTemperature, - fields::diffusion::phaseDiffusivityMultiplier >; - - using DispersionAccessors = - StencilMaterialAccessors< constitutive::DispersionBase, - fields::dispersion::dispersivity >; - - using PorosityAccessors = - StencilMaterialAccessors< constitutive::PorosityBase, - fields::porosity::referencePorosity >; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @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] diffusionAccessors - * @param[in] dispersionAccessors - * @param[in] porosityAccessors - * @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 - */ - DiffusionDispersionFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - DiffusionAccessors const & diffusionAccessors, - DispersionAccessors const & dispersionAccessors, - PorosityAccessors const & porosityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : FaceBasedAssemblyKernelBase( numPhases, - rankOffset, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_phaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} ) ), - m_phaseDens( multiFluidAccessors.get( fields::multifluid::phaseDensity {} ) ), - m_dPhaseDens( multiFluidAccessors.get( fields::multifluid::dPhaseDensity {} ) ), - m_diffusivity( diffusionAccessors.get( fields::diffusion::diffusivity {} ) ), - m_dDiffusivity_dTemp( diffusionAccessors.get( fields::diffusion::dDiffusivity_dTemperature {} ) ), - m_phaseDiffusivityMultiplier( diffusionAccessors.get( fields::diffusion::phaseDiffusivityMultiplier {} ) ), - m_dispersivity( dispersionAccessors.get( fields::dispersion::dispersivity {} ) ), - m_referencePorosity( porosityAccessors.get( fields::porosity::referencePorosity {} ) ), - m_stencilWrapper( stencilWrapper ), - m_seri( stencilWrapper.getElementRegionIndices() ), - m_sesri( stencilWrapper.getElementSubRegionIndices() ), - m_sei( stencilWrapper.getElementIndices() ) - { } - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - 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, localIndex numElems ) - : stencilSize( size ), - numConnectedElems( numElems ), - dofColIndices( size * numDof ), - localFlux( numElems * numEqn ), - localFluxJacobian( numElems * numEqn, size * numDof ) - {} - - // Stencil information - - /// Stencil size for a given connection - localIndex const stencilSize; - /// Number of elements connected at a given connection - localIndex const numConnectedElems; - - /// Transmissibility - real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; - /// Derivatives of transmissibility with respect to pressure - real64 dTrans_dTemp[maxNumConns][numFluxSupportPoints]{}; - - // 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 equations except volume balance) - stackArray1d< real64, maxNumElems * numEqn > localFlux; - /// Storage for the face local Jacobian matrix - stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; - }; - - - /** - * @brief Getter for the stencil size at this connection - * @param[in] iconn the connection index - * @return the size of the stencil at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex stencilSize( localIndex const iconn ) const - { return m_sei[iconn].size(); } - - /** - * @brief Getter for the number of elements at this connection - * @param[in] iconn the connection index - * @return the number of elements at this connection - */ - GEOS_HOST_DEVICE - inline - localIndex numPointsInFlux( localIndex const iconn ) const - { return m_stencilWrapper.numPointsInFlux( iconn ); } - - - /** - * @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 - { - // set degrees of freedom indices for this face - for( integer i = 0; i < stack.stencilSize; ++i ) - { - globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[i * numDof + jdof] = offset + jdof; - } - } - } - - /** - * @brief Compute the local diffusion 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] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] diffusionFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void computeDiffusionFlux( localIndex const iconn, - StackVariables & stack, - FUNC && diffusionFluxKernelOp = NoOpFunc{} ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - // first, compute the transmissibilities at this face - m_stencilWrapper.computeWeights( iconn, - m_diffusivity, - m_dDiffusivity_dTemp, - stack.transmissibility, - stack.dTrans_dTemp ); - - - localIndex k[numFluxSupportPoints]{}; - localIndex connectionIndex = 0; - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - /// cell indices - localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // clear working arrays - real64 diffusionFlux[numComp]{}; - real64 dDiffusionFlux_dP[numFluxSupportPoints][numComp]{}; - real64 dDiffusionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; - real64 dDens_dC[numComp]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - //***** calculation of flux ***** - // loop over phases, compute and upwind phase flux and sum contributions to each component's flux - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - - // loop over components - for( integer ic = 0; ic < numComp; ++ic ) - { - - real64 compFracGrad = 0.0; - real64 dCompFracGrad_dP[numFluxSupportPoints]{}; - real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; - - // compute the component fraction gradient using the diffusion transmissibility - computeCompFractionGradient( ip, ic, - seri, sesri, sei, - trans, - compFracGrad, - dCompFracGrad_dP, - dCompFracGrad_dC ); - - // choose upstream cell for composition upwinding - localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; - - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - // computation of the upwinded mass flux - real64 const upwindCoefficient = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_phaseVolFrac[er_up][esr_up][ei_up][ip]; - diffusionFlux[ic] += upwindCoefficient * compFracGrad; - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) - { - dDiffusionFlux_dP[ke][ic] += upwindCoefficient * dCompFracGrad_dP[ke]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDiffusionFlux_dC[ke][ic][jc] += upwindCoefficient * dCompFracGrad_dC[ke][jc]; - } - } - - // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions - real64 const dUpwindCoefficient_dP = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] - + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dP] ); - dDiffusionFlux_dP[k_up][ic] += dUpwindCoefficient_dP * compFracGrad; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er_up][esr_up][ei_up], - m_dPhaseDens[er_up][esr_up][ei_up][0][ip], - dDens_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - real64 const dUpwindCoefficient_dC = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - ( dDens_dC[jc] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] - + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dC+jc] ); - dDiffusionFlux_dC[k_up][ic][jc] += dUpwindCoefficient_dC * compFracGrad; - } - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - diffusionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, - k_up, seri[k_up], sesri[k_up], sei[k_up], - compFracGrad, upwindCoefficient ); - - } // loop over components - } // loop over phases - - // add diffusion flux to local flux and local flux jacobian - addToLocalFluxAndJacobian( k, - stack, - diffusionFlux, - dDiffusionFlux_dP, - dDiffusionFlux_dC ); - - connectionIndex++; - } // loop over k[1] - } // loop over k[0] - } - - /** - * @brief Compute the local dispersion 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] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] dispersionFluxKernelOp the function used to customize the computation of the component fluxes - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void computeDispersionFlux( localIndex const iconn, - StackVariables & stack, - FUNC && dispersionFluxKernelOp = NoOpFunc{} ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - // first, compute the transmissibilities at this face - // note that the dispersion tensor is lagged in iteration - m_stencilWrapper.computeWeights( iconn, - m_dispersivity, - m_dispersivity, // this is just to pass something, but the resulting derivative won't be used - stack.transmissibility, - stack.dTrans_dTemp ); // will not be used - - - localIndex k[numFluxSupportPoints]{}; - localIndex connectionIndex = 0; - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - /// cell indices - localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - // clear working arrays - real64 dispersionFlux[numComp]{}; - real64 dDispersionFlux_dP[numFluxSupportPoints][numComp]{}; - real64 dDispersionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; - real64 dDens_dC[numComp]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - //***** calculation of flux ***** - // loop over phases, compute and upwind phase flux and sum contributions to each component's flux - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - - // loop over components - for( integer ic = 0; ic < numComp; ++ic ) - { - - real64 compFracGrad = 0.0; - real64 dCompFracGrad_dP[numFluxSupportPoints]{}; - real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; - - // compute the component fraction gradient using the dispersion transmissibility - computeCompFractionGradient( ip, ic, - seri, sesri, sei, - trans, - compFracGrad, - dCompFracGrad_dP, - dCompFracGrad_dC ); - - // choose upstream cell for composition upwinding - localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; - - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - // computation of the upwinded mass flux - dispersionFlux[ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * compFracGrad; - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) - { - dDispersionFlux_dP[ke][ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dP[ke]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDispersionFlux_dC[ke][ic][jc] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dC[ke][jc]; - } - } - - // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions - dDispersionFlux_dP[k_up][ic] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * compFracGrad; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er_up][esr_up][ei_up], - m_dPhaseDens[er_up][esr_up][ei_up][0][ip], - dDens_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dDispersionFlux_dC[k_up][ic][jc] += dDens_dC[jc] * compFracGrad; - } - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - dispersionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, - k_up, seri[k_up], sesri[k_up], sei[k_up], - compFracGrad ); - - } // loop over components - } // loop over phases - - // add dispersion flux to local flux and local flux jacobian - addToLocalFluxAndJacobian( k, - stack, - dispersionFlux, - dDispersionFlux_dP, - dDispersionFlux_dC ); - - connectionIndex++; - } // loop over k[1] - } // loop over k[0] - } - - /** - * @brief Compute the component fraction gradient at this interface - * @param[in] ip the phase index - * @param[in] ic the component index - * @param[in] seri the region indices - * @param[in] sesri the subregion indices - * @param[in] sei the element indices - * @param[out] compFracGrad the component fraction gradient - * @param[out] dCompFracGrad_dP the derivatives of the component fraction gradient wrt pressure - * @param[out] dCompFracGrad_dC the derivatives of the component fraction gradient wrt component densities - */ - GEOS_HOST_DEVICE - inline - void computeCompFractionGradient( integer const ip, - integer const ic, - localIndex const (&seri)[numFluxSupportPoints], - localIndex const (&sesri)[numFluxSupportPoints], - localIndex const (&sei)[numFluxSupportPoints], - real64 const (&trans)[numFluxSupportPoints], - real64 & compFracGrad, - real64 (& dCompFracGrad_dP)[numFluxSupportPoints], - real64 (& dCompFracGrad_dC)[numFluxSupportPoints][numComp] ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - real64 dCompFrac_dC[numComp]{}; - - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - compFracGrad += trans[i] * m_phaseCompFrac[er][esr][ei][0][ip][ic]; - dCompFracGrad_dP[i] += trans[i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP]; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - m_dPhaseCompFrac[er][esr][ei][0][ip][ic], - dCompFrac_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFracGrad_dC[i][jc] += trans[i] * dCompFrac_dC[jc]; - } - } - } - - /** - * @brief Add the local diffusion/dispersion flux contributions to the residual and Jacobian - * @param[in] k the cell indices - * @param[in] stack the stack variables - * @param[in] flux the diffusion/dispersion flux - * @param[in] dFlux_dP the derivative of the diffusion/dispersion flux wrt pressure - * @param[in] dFlux_dC the derivative of the diffusion/dispersion flux wrt compositions - */ - GEOS_HOST_DEVICE - inline - void addToLocalFluxAndJacobian( localIndex const (&k)[numFluxSupportPoints], - StackVariables & stack, - real64 const (&flux)[numComp], - real64 const (&dFlux_dP)[numFluxSupportPoints][numComp], - real64 const (&dFlux_dC)[numFluxSupportPoints][numComp][numComp] ) const - { - // loop over components - for( integer ic = 0; ic < numComp; ++ic ) - { - // finally, increment local flux and local Jacobian - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - stack.localFlux[eqIndex0] += m_dt * flux[ic]; - stack.localFlux[eqIndex1] -= m_dt * flux[ic]; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dFlux_dP[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dFlux_dP[ke][ic]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - localIndex const localDofIndexComp = localDofIndexPres + jc + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dFlux_dC[ke][ic][jc]; - stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dFlux_dC[ke][ic][jc]; - } - } - } - } - - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - inline - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = NoOpFunc{} ) const - { - using namespace compositionalMultiphaseUtilities; - - if( m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::TotalMassEquation ) ) - { - // Apply equation/variable change transformation(s) - stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); - shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof*stack.stencilSize, stack.numConnectedElems, - stack.localFluxJacobian, work ); - shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, - stack.localFlux ); - } - - // add contribution to residual and jacobian into: - // - the component mass balance equations (i = 0 to i = numComp-1) - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - for( integer i = 0; i < stack.numConnectedElems; ++i ) - { - if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); - - for( integer ic = 0; ic < numComp; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], stack.localFlux[i * numEqn + ic] ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + ic, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), - stack.stencilSize * numDof ); - } - - // call the lambda to assemble additional terms, such as thermal terms - assemblyKernelOp( i, localRow ); - } - } - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numConnections the number of connections - * @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 numConnections, - integer const hasDiffusion, - integer const hasDispersion, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - kernelComponent.numPointsInFlux( iconn ) ); - - kernelComponent.setup( iconn, stack ); - if( hasDiffusion ) - { - kernelComponent.computeDiffusionFlux( iconn, stack ); - } - if( hasDispersion ) - { - kernelComponent.computeDispersionFlux( iconn, stack ); - } - kernelComponent.complete( iconn, stack ); - } ); - } - -protected: - - /// Views on phase volume fraction - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseVolFrac; - - /// Views on phase densities - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseDens; - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseDens; - - /// Views on diffusivity - ElementViewConst< arrayView3d< real64 const > > const m_diffusivity; - ElementViewConst< arrayView3d< real64 const > > const m_dDiffusivity_dTemp; - ElementViewConst< arrayView3d< real64 const > > const m_phaseDiffusivityMultiplier; - - /// Views on dispersivity - ElementViewConst< arrayView3d< real64 const > > const m_dispersivity; - - /// View on the reference porosity - ElementViewConst< arrayView1d< real64 const > > const m_referencePorosity; - - // Stencil information - - /// Reference to the stencil wrapper - STENCILWRAPPER const m_stencilWrapper; - - /// Connection to element maps - typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; - -}; - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernelFactory - */ -class DiffusionDispersionFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @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 string to get the element degrees of freedom numbers - * @param[in] hasDiffusion flag specifying whether diffusion is used or not - * @param[in] hasDispersion flag specifying whether dispersion is used or not - * @param[in] solverName the name of the solver - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasDiffusion, - integer const hasDispersion, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - 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() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using kernelType = DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); - typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); - typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, stencilWrapper, - dofNumberAccessor, compFlowAccessors, multiFluidAccessors, - diffusionAccessors, dispersionAccessors, porosityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), - hasDiffusion, hasDispersion, - kernel ); - } ); - } -}; - - -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public FaceBasedAssemblyKernel< NUM_COMP, - NUM_DOF, - BoundaryStencilWrapper > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_numPhases; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_ghostRank; - using AbstractBase::m_gravCoef; - using AbstractBase::m_pres; - using AbstractBase::m_phaseCompFrac; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dCompFrac_dCompDens; - using AbstractBase::m_localMatrix; - using AbstractBase::m_localRhs; - using AbstractBase::m_kernelFlags; - - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, BoundaryStencilWrapper >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::m_stencilWrapper; - using Base::m_phaseMob; - using Base::m_dPhaseMob; - using Base::m_phaseMassDens; - using Base::m_dPhaseMassDens; - using Base::m_permeability; - using Base::m_dPerm_dPres; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid 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 - */ - DirichletFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_facePres( faceManager.getField< fields::flow::facePressure >() ), - m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), - m_faceCompFrac( faceManager.getField< fields::flow::faceGlobalCompFraction >() ), - m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), - m_fluidWrapper( fluidWrapper ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - 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 GEOS_UNUSED_PARAM( size ), - localIndex GEOS_UNUSED_PARAM( numElems )) {} - - // Transmissibility - real64 transmissibility = 0.0; - - // Component fluxes and derivatives - - /// Component fluxes - real64 compFlux[numComp]{}; - /// Derivatives of component fluxes wrt pressure - real64 dCompFlux_dP[numComp]{}; - /// Derivatives of component fluxes wrt component densities - real64 dCompFlux_dC[numComp][numComp]{}; - - // Local degrees of freedom and local residual/jacobian - - /// Indices of the matrix rows/columns corresponding to the dofs in this face - globalIndex dofColIndices[numDof]{}; - - /// Storage for the face local residual vector - real64 localFlux[numEqn]{}; - /// Storage for the face local Jacobian matrix - real64 localFluxJacobian[numEqn][numDof]{}; - - }; - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const iconn, - StackVariables & stack ) const - { - globalIndex const offset = - m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[jdof] = offset + jdof; - } - } - - - /** - * @brief Compute the local Dirichlet face 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] iconn the connection 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 - void computeFlux( localIndex const iconn, - StackVariables & stack, - FUNC && compFluxKernelOp = NoOpFunc{} ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - using Order = BoundaryStencil::Order; - - localIndex const er = m_seri( iconn, Order::ELEM ); - localIndex const esr = m_sesri( iconn, Order::ELEM ); - localIndex const ei = m_sei( iconn, Order::ELEM ); - localIndex const kf = m_sei( iconn, Order::FACE ); - - // Step 1: compute the transmissibility at the boundary face - - real64 dTrans_dPerm[3]{}; - m_stencilWrapper.computeWeights( iconn, - m_permeability, - stack.transmissibility, - dTrans_dPerm ); - real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); - - // Step 2: compute the fluid properties on the face - // This is needed to get the phase mass density and the phase comp fraction at the face - // Because we approximate the face mobility using the total element mobility - - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseFrac( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseDens( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseMassDens( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseVisc( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseEnthalpy( 1, 1, m_numPhases ); - StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseInternalEnergy( 1, 1, m_numPhases ); - StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES * NUM_COMP, - constitutive::multifluid::LAYOUT_PHASE_COMP > facePhaseCompFrac( 1, 1, m_numPhases, NUM_COMP ); - real64 faceTotalDens = 0.0; - - constitutive::MultiFluidBase::KernelWrapper::computeValues( m_fluidWrapper, - m_facePres[kf], - m_faceTemp[kf], - m_faceCompFrac[kf], - facePhaseFrac[0][0], - facePhaseDens[0][0], - facePhaseMassDens[0][0], - facePhaseVisc[0][0], - facePhaseEnthalpy[0][0], - facePhaseInternalEnergy[0][0], - facePhaseCompFrac[0][0], - faceTotalDens ); - - // Step 3: loop over phases, compute and upwind phase flux and sum contributions to each component's flux - - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - - // working variables - real64 dDensMean_dC[numComp]{}; - real64 dF_dC[numComp]{}; - real64 dProp_dC[numComp]{}; - - real64 phaseFlux = 0.0; // for the lambda - real64 dPhaseFlux_dP = 0.0; - real64 dPhaseFlux_dC[numComp]{}; - - - // Step 3.1: compute the average phase mass density at the face - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - m_dPhaseMassDens[er][esr][ei][0][ip], - dProp_dC, - Deriv::dC ); - - // average density and derivatives - real64 const densMean = 0.5 * ( m_phaseMassDens[er][esr][ei][0][ip] + facePhaseMassDens[0][0][ip] ); - real64 const dDensMean_dP = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDensMean_dC[jc] = 0.5 * dProp_dC[jc]; - } - - - // Step 3.2: compute the (TPFA) potential difference at the face - - real64 const gravTimesDz = m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]; - real64 const potDif = m_pres[er][esr][ei] - m_facePres[kf] - densMean * gravTimesDz; - real64 const f = stack.transmissibility * potDif; - real64 const dF_dP = stack.transmissibility * ( 1.0 - dDensMean_dP * gravTimesDz ) + dTrans_dPres * potDif; - for( integer jc = 0; jc < numComp; ++jc ) - { - dF_dC[jc] = -stack.transmissibility * dDensMean_dC[jc] * gravTimesDz; - } - - // Step 3.3: computation of the mobility - // We do that before the if/else statement to be able to pass it to the compFluxOpKernel - - // recomputing the exact mobility at the face would be quite complex, as it would require: - // 1) computing the saturation - // 2) computing the relperm - // 3) computing the mobility as \lambda_p = \rho_p kr_p( S_p ) / \mu_p - // the second step in particular would require yet another dispatch to get the relperm model - // so, for simplicity, we approximate the face mobility as - // \lambda^approx_p = \rho_p S_p / \mu_p - // = \rho_p ( (nu_p / rho_p) * rho_t ) / \mu_p (plugging the expression of saturation) - // = \nu_p * rho_t / \mu_p - // fortunately, we don't need the derivatives - real64 const facePhaseMob = ( facePhaseFrac[0][0][ip] > 0.0 ) - ? facePhaseFrac[0][0][ip] * faceTotalDens / facePhaseVisc[0][0][ip] - : 0.0; - - // *** upwinding *** - // Step 3.4: upwinding based on the sign of the phase potential gradient - // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way - - if( potDif >= 0 ) // the element is upstream - { - - // compute the phase flux and derivatives using the element mobility - phaseFlux = m_phaseMob[er][esr][ei][ip] * f; - dPhaseFlux_dP = m_phaseMob[er][esr][ei][ip] * dF_dP + m_dPhaseMob[er][esr][ei][ip][Deriv::dP] * f; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[jc] = - m_phaseMob[er][esr][ei][ip] * dF_dC[jc] + m_dPhaseMob[er][esr][ei][ip][Deriv::dC+jc] * f; - } - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = - m_phaseCompFrac[er][esr][ei][0][ip]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = - m_dPhaseCompFrac[er][esr][ei][0][ip]; - - // compute component fluxes and derivatives using element composition - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - stack.compFlux[ic] += phaseFlux * ycp; - stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; - - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - dPhaseCompFracSub[ic], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp + phaseFlux * dProp_dC[jc]; - } - } - - } - else // the face is upstream - { - - // compute the phase flux and derivatives using the approximated face mobility - // we only have to take derivatives of the potential gradient in this case - phaseFlux = facePhaseMob * f; - dPhaseFlux_dP = facePhaseMob * dF_dP; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[jc] = facePhaseMob * dF_dC[jc]; - } - - // compute component fluxes and derivatives using the face composition - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = facePhaseCompFrac[0][0][ip][ic]; - stack.compFlux[ic] += phaseFlux * ycp; - stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp; - } - } - } - - // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - compFluxKernelOp( ip, er, esr, ei, kf, f, - facePhaseMob, facePhaseEnthalpy[0][0], facePhaseCompFrac[0][0], - phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); - - } - - // *** end of upwinding - - // Step 4: populate local flux vector and derivatives - for( integer ic = 0; ic < numComp; ++ic ) - { - stack.localFlux[ic] = m_dt * stack.compFlux[ic]; - stack.localFluxJacobian[ic][0] = m_dt * stack.dCompFlux_dP[ic]; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.localFluxJacobian[ic][jc+1] = m_dt * stack.dCompFlux_dC[ic][jc]; - } - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = NoOpFunc{} ) const - { - using namespace compositionalMultiphaseUtilities; - using Order = BoundaryStencil::Order; - - if( AbstractBase::m_kernelFlags.isSet( FaceBasedAssemblyKernelFlags::TotalMassEquation ) ) - { - // Apply equation/variable change transformation(s) - real64 work[numDof]{}; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localFluxJacobian, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localFlux ); - } - - // add contribution to residual and jacobian into: - // - the component mass balance equations (i = 0 to i = numComp-1) - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - if( m_ghostRank[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( AbstractBase::m_localMatrix.numRows(), localRow + numComp ); - - for( integer ic = 0; ic < numComp; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + ic], stack.localFlux[ic] ); - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + ic, - stack.dofColIndices, - stack.localFluxJacobian[ic], - numDof ); - } - - // call the lambda to assemble additional terms, such as thermal terms - assemblyKernelOp( localRow ); - } - } - -protected: - - /// Views on face pressure, temperature, and composition - arrayView1d< real64 const > const m_facePres; - arrayView1d< real64 const > const m_faceTemp; - arrayView2d< real64 const, compflow::USD_COMP > const m_faceCompFrac; - - /// View on the face gravity coefficient - arrayView1d< real64 const > const m_faceGravCoef; - - /// Reference to the fluid wrapper - FLUIDWRAPPER const m_fluidWrapper; - -}; - - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -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 string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the boundary stencil wrapper - * @param[in] fluidBase the multifluid constitutive model - * @param[in] dt time step size - * @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, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - string const & dofKey, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - BoundaryStencilWrapper const & stencilWrapper, - constitutive::MultiFluidBase & fluidBase, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutive::constitutiveComponentUpdatePassThru( fluidBase, numComps, [&]( auto & fluid, auto NC ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); - - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - // for now, we neglect capillary pressure in the kernel - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using kernelType = DirichletFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, - dofNumberAccessor, compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - - -/******************************** CFLFluxKernel ********************************/ - -/** - * @brief Functions to compute the (outflux) total volumetric flux needed in the calculation of CFL numbers - */ -struct CFLFluxKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - template< typename VIEWTYPE > - using ElementView = ElementRegionManager::ElementView< VIEWTYPE >; - - using CompFlowAccessors = - StencilAccessors< fields::flow::pressure, - fields::flow::gravityCoefficient, - fields::flow::phaseVolumeFraction, - fields::flow::phaseOutflux, - fields::flow::componentOutflux >; - - using MultiFluidAccessors = - StencilMaterialAccessors< constitutive::MultiFluidBase, - fields::multifluid::phaseViscosity, - fields::multifluid::phaseDensity, - fields::multifluid::phaseMassDensity, - fields::multifluid::phaseCompFraction >; - - using PermeabilityAccessors = - StencilMaterialAccessors< constitutive::PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure >; - - - using RelPermAccessors = - StencilMaterialAccessors< constitutive::RelativePermeabilityBase, fields::relperm::phaseRelPerm >; - - template< integer NC, localIndex NUM_ELEMS, localIndex maxStencilSize > - GEOS_HOST_DEVICE - inline - static void - compute( integer const numPhases, - localIndex const stencilSize, - real64 const dt, - arraySlice1d< localIndex const > const seri, - arraySlice1d< localIndex const > const sesri, - arraySlice1d< localIndex const > const sei, - real64 const (&transmissibility)[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const & phaseRelPerm, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseVisc, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, - ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); - - template< integer NC, typename STENCILWRAPPER_TYPE > - static void - launch( integer const numPhases, - real64 const dt, - STENCILWRAPPER_TYPE const & stencil, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const > > const & permeability, - ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, - ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const & phaseRelPerm, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseVisc, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, - ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); -}; - -/******************************** CFLKernel ********************************/ - -/** - * @brief Functions to compute the CFL number using the phase volumetric outflux and the component mass outflux in each cell - */ -struct CFLKernel -{ - - static constexpr real64 minPhaseMobility = 1e-12; - static constexpr real64 minComponentFraction = 1e-12; - - template< integer NP > - GEOS_HOST_DEVICE - inline - static void - computePhaseCFL( real64 const poreVol, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, - arraySlice1d< real64 const, constitutive::relperm::USD_RELPERM - 2 > phaseRelPerm, - arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > dPhaseRelPerm_dPhaseVolFrac, - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseVisc, - arraySlice1d< real64 const, compflow::USD_PHASE- 1 > phaseOutflux, - real64 & phaseCFLNumber ); - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - computeCompCFL( real64 const poreVol, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compDens, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compFrac, - arraySlice1d< real64 const, compflow::USD_COMP - 1 > compOutflux, - real64 & compCFLNumber ); - - template< integer NC, integer NP > - static void - launch( localIndex const size, - arrayView1d< real64 const > const & volume, - arrayView2d< real64 const > const & porosity, - arrayView2d< real64 const, compflow::USD_COMP > const & compDens, - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, - arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, - arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseVisc, - arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, - arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, - arrayView1d< real64 > const & phaseCFLNumber, - arrayView1d< real64 > const & compCFLNumber, - real64 & maxPhaseCFLNumber, - real64 & maxCompCFLNumber ); - -}; - -/******************************** AquiferBCKernel ********************************/ - -/** - * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian - */ -struct AquiferBCKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using CompFlowAccessors = - StencilAccessors< fields::ghostRank, - fields::flow::pressure, - fields::flow::pressure_n, - fields::flow::gravityCoefficient, - fields::flow::phaseVolumeFraction, - fields::flow::dPhaseVolumeFraction, - fields::flow::dGlobalCompFraction_dGlobalCompDensity >; - - using MultiFluidAccessors = - StencilMaterialAccessors< constitutive::MultiFluidBase, - fields::multifluid::phaseDensity, - fields::multifluid::dPhaseDensity, - fields::multifluid::phaseCompFraction, - fields::multifluid::dPhaseCompFraction >; - - template< integer NC > - GEOS_HOST_DEVICE - inline - static void - compute( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - real64 const aquiferVolFlux, - real64 const dAquiferVolFlux_dPres, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens, - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, - arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, - real64 const dt, - real64 ( &localFlux )[NC], - real64 ( &localFluxJacobian )[NC][NC+1] ); - - template< integer NC > - static void - launch( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - integer const useTotalMassEquation, - BoundaryStencil const & stencil, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & pres_n, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - real64 const timeAtBeginningOfStep, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ); - -}; - -} // namespace isothermalCompositionalMultiphaseFVMKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/FlowSolverBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp similarity index 74% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/FlowSolverBaseKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp index 4c3b0f0df36..6d930e5d592 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/FlowSolverBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/MinPoreVolumeMaxPorosityKernel.hpp @@ -14,11 +14,11 @@ */ /** - * @file FlowSolverBaseKernels.hpp + * @file MinPoreVolumeMaxPorosityKernel.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLOWSOLVERBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLOWSOLVERBASEKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_MINPOREVOLUMEMAXPOROSITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_MINPOREVOLUMEMAXPOROSITYKERNEL_HPP #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" @@ -33,9 +33,6 @@ namespace flowSolverBaseKernels /// Threshold for the min pore volume (below, a warning is issued) static constexpr real64 poreVolumeThreshold = 1e-4; -template< typename VIEWTYPE > -using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - /** * @struct MinPoreVolumeMaxPorosityKernel * @brief Kernel to compute the min pore volume and the max porosity in a subRegion @@ -106,47 +103,8 @@ struct MinPoreVolumeMaxPorosityKernel } }; -/** - * @brief - * - * @tparam STENCILWRAPPER - */ -template< typename STENCILWRAPPER > -struct stencilWeightsUpdateKernel -{ - /** - * @brief - * - * @param stencilWrappper - * @param hydraulicAperture - */ - inline static void prepareStencilWeights( STENCILWRAPPER & stencilWrapper, - ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) - { - forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - stencilWrapper.removeHydraulicApertureContribution( iconn, hydraulicAperture ); - } ); - } - - /** - * @brief - * - * @param stencilWrappper - * @param hydraulicAperture - */ - inline static void updateStencilWeights( STENCILWRAPPER & stencilWrapper, - ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) - { - forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - stencilWrapper.addHydraulicApertureContribution( iconn, hydraulicAperture ); - } ); - } -}; - } // namespace flowSolverBaseKernels } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLOWSOLVERBASEKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_MINPOREVOLUMEMAXPOROSITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp deleted file mode 100644 index d51885d0443..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp +++ /dev/null @@ -1,897 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASEKERNELS_HPP - -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" -#include "constitutive/solid/CoupledSolidBase.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" -#include "codingUtilities/Utilities.hpp" - -namespace geos -{ - -namespace singlePhaseBaseKernels -{ - -/******************************** MobilityKernel ********************************/ - -struct MobilityKernel -{ - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & dDens_dPres, - real64 const & visc, - real64 const & dVisc_dPres, - real64 & mob, - real64 & dMob_dPres ) - { - mob = dens / visc; - dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; - } - - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & visc, - real64 & mob ) - { - mob = dens / visc; - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & dDens_dPres, - arrayView2d< real64 const > const & visc, - arrayView2d< real64 const > const & dVisc_dPres, - arrayView1d< real64 > const & mob, - arrayView1d< real64 > const & dMob_dPres ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - dDens_dPres[a][0], - visc[a][0], - dVisc_dPres[a][0], - mob[a], - dMob_dPres[a] ); - } ); - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & visc, - arrayView1d< real64 > const & mob ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - visc[a][0], - mob[a] ); - } ); - } -}; - -/******************************** ElementBasedAssemblyKernel ********************************/ - -/** - * @class ElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation - */ -template< typename SUBREGION_TYPE, integer NUM_DOF > -class ElementBasedAssemblyKernel -{ - -public: - - /// 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] 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( globalIndex const rankOffset, - string const dofKey, - SUBREGION_TYPE const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : - m_rankOffset( rankOffset ), - m_dofNumber( subRegion.template getReference< array1d< globalIndex > >( dofKey ) ), - m_elemGhostRank( subRegion.ghostRank() ), - m_volume( subRegion.getElementVolume() ), - m_deltaVolume( subRegion.template getField< fields::flow::deltaVolume >() ), - m_porosity( solid.getPorosity() ), - m_dPoro_dPres( solid.getDporosity_dPressure() ), - m_density( fluid.density() ), - m_dDensity_dPres( fluid.dDensity_dPressure() ), - m_mass_n( subRegion.template getField< fields::flow::mass_n >() ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables - { -public: - - // Pore volume information - - /// Pore volume at time n+1 - real64 poreVolume = 0.0; - - /// Derivative of pore volume with respect to pressure - real64 dPoreVolume_dPres = 0.0; - - // Residual information - - /// Index of the local row corresponding to this element - localIndex localRow = -1; - - /// Index of the matrix row/column corresponding to the dof in this element - globalIndex dofIndices[numDof]{}; - - /// Storage for the element local residual vector - real64 localResidual[numEqn]{}; - - /// Storage for the element local Jacobian matrix - 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 pore volume - stack.poreVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * m_porosity[ei][0]; - stack.dPoreVolume_dPres = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; - - // 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] kernelOp the function used to customize the kernel - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - // Residual contribution is mass conservation in the cell - stack.localResidual[0] = stack.poreVolume * m_density[ei][0] - m_mass_n[ei]; - - // Derivative of residual wrt to pressure in the cell - stack.localJacobian[0][0] = stack.dPoreVolume_dPres * m_density[ei][0] + m_dDensity_dPres[ei][0] * stack.poreVolume; - - // Customize the kernel with this lambda - kernelOp(); - } - - /** - * @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 global residual and jacobian (no need for atomics here) - m_localMatrix.template addToRow< serialAtomic >( stack.localRow, - stack.dofIndices, - stack.localJacobian[0], - numDof ); - m_localRhs[stack.localRow] += stack.localResidual[0]; - - } - - /** - * @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.complete( ei, stack ); - } ); - } - -protected: - - /// 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; - arrayView1d< real64 const > const m_deltaVolume; - - /// Views on the porosity - arrayView2d< real64 const > const m_porosity; - arrayView2d< real64 const > const m_dPoro_dPres; - - /// Views on density - arrayView2d< real64 const > const m_density; - arrayView2d< real64 const > const m_dDensity_dPres; - - /// View on mass - arrayView1d< real64 const > const m_mass_n; - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; - -}; - -/** - * @class SurfaceElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion - */ -class SurfaceElementBasedAssemblyKernel : public ElementBasedAssemblyKernel< SurfaceElementSubRegion, 1 > -{ - -public: - - using Base = ElementBasedAssemblyKernel< SurfaceElementSubRegion, 1 >; - - /** - * @brief Constructor - * @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 - */ - SurfaceElementBasedAssemblyKernel( globalIndex const rankOffset, - string const dofKey, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ) - , m_creationMass( subRegion.getField< fields::flow::massCreated >() ) - {} - - /** - * @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, - Base::StackVariables & stack ) const - { - Base::computeAccumulation( ei, stack, [&] () - { - if( Base::m_mass_n[ei] > 1.1 * m_creationMass[ei] ) - { - stack.localResidual[0] += m_creationMass[ei] * 0.25; - } - } ); - } - -protected: - - arrayView1d< real64 const > const m_creationMass; - -}; - -/** - * @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[in] solid the solid 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, - CellElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_DOF = 1; - - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF > - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); - } - - /** - * @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[in] solid the solid 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, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - SurfaceElementBasedAssemblyKernel - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - SurfaceElementBasedAssemblyKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > -{ -public: - - using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; - 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, - ElementSubRegionBase const & subRegion, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_mass_n( subRegion.template getField< fields::flow::mass_n >() ) - {} - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); - stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; - stack.localNormalizer[0] += massNormalizer; - } - - -protected: - - /// View on mass at the previous converged time step - arrayView1d< real64 const > const m_mass_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @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 element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( physicsSolverBaseKernels::NormType const normType, - globalIndex const rankOffset, - string const dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - real64 const minNormalizer, - real64 (& residualNorm)[1], - real64 (& residualNormalizer)[1] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, minNormalizer ); - if( normType == physicsSolverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - } - -}; - -/******************************** SolutionCheckKernel ********************************/ - -struct SolutionCheckKernel -{ - template< typename POLICY > - static std::pair< integer, real64 > launch( arrayView1d< real64 const > const & localSolution, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< integer const > const & ghostRank, - arrayView1d< real64 const > const & pres, - real64 const scalingFactor ) - { - RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegativePressures( 0 ); - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); - - forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) - { - localIndex const lid = dofNumber[ei] - rankOffset; - real64 const newPres = pres[ei] + scalingFactor * localSolution[lid]; - - if( newPres < 0.0 ) - { - numNegativePressures += 1; - minPres.min( newPres ); - } - } - - } ); - - return { numNegativePressures.get(), minPres.get() }; - } - -}; - -/******************************** ScalingForSystemSolutionKernel ********************************/ - -struct ScalingForSystemSolutionKernel -{ - template< typename POLICY > - static std::pair< real64, real64 > launch( arrayView1d< real64 const > const & localSolution, - globalIndex const rankOffset, - arrayView1d< globalIndex const > const & dofNumber, - arrayView1d< integer const > const & ghostRank, - real64 const maxAbsolutePresChange ) - { - RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > scalingFactor( 1.0 ); - RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPres( 0.0 ); - - forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) mutable - { - if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) - { - localIndex const lid = dofNumber[ei] - rankOffset; - - // compute the change in pressure - real64 const absPresChange = LvArray::math::abs( localSolution[lid] ); - maxDeltaPres.max( absPresChange ); - - // maxAbsolutePresChange <= 0.0 means that scaling is disabled, and we are only collecting maxDeltaPres in this kernel - if( maxAbsolutePresChange > 0.0 && absPresChange > maxAbsolutePresChange ) - { - real64 const presScalingFactor = maxAbsolutePresChange / absPresChange; - scalingFactor.min( presScalingFactor ); - } - } - - } ); - - return { scalingFactor.get(), maxDeltaPres.get() }; - } - -}; - -/******************************** StatisticsKernel ********************************/ - -struct StatisticsKernel -{ - static void - saveDeltaPressure( localIndex const size, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & initPres, - arrayView1d< real64 > const & deltaPres ) - { - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - deltaPres[ei] = pres[ei] - initPres[ei]; - } ); - } - - static void - launch( localIndex const size, - arrayView1d< integer const > const & elemGhostRank, - arrayView1d< real64 const > const & volume, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & deltaPres, - arrayView1d< real64 const > const & temp, - arrayView1d< real64 const > const & refPorosity, - arrayView2d< real64 const > const & porosity, - arrayView2d< real64 const > const & density, - real64 & minPres, - real64 & avgPresNumerator, - real64 & maxPres, - real64 & minDeltaPres, - real64 & maxDeltaPres, - real64 & minTemp, - real64 & avgTempNumerator, - real64 & maxTemp, - real64 & totalUncompactedPoreVol, - real64 & totalPoreVol, - real64 & totalMass ) - { - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); - - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); - - RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); - RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( -LvArray::NumericLimits< real64 >::max ); - - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalPoreVol( 0.0 ); - RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalMass( 0.0 ); - - forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) - { - if( elemGhostRank[ei] >= 0 ) - { - return; - } - - // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages - real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; - real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; - - subRegionMinPres.min( pres[ei] ); - subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; - subRegionMaxPres.max( pres[ei] ); - - subRegionMinDeltaPres.min( deltaPres[ei] ); - subRegionMaxDeltaPres.max( deltaPres[ei] ); - - subRegionMinTemp.min( temp[ei] ); - subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; - subRegionMaxTemp.max( temp[ei] ); - - subRegionTotalUncompactedPoreVol += uncompactedPoreVol; - subRegionTotalPoreVol += dynamicPoreVol; - subRegionTotalMass += dynamicPoreVol * density[ei][0]; - } ); - - minPres = subRegionMinPres.get(); - avgPresNumerator = subRegionAvgPresNumerator.get(); - maxPres = subRegionMaxPres.get(); - - minDeltaPres = subRegionMinDeltaPres.get(); - maxDeltaPres = subRegionMaxDeltaPres.get(); - - minTemp = subRegionMinTemp.get(); - avgTempNumerator = subRegionAvgTempNumerator.get(); - maxTemp = subRegionMaxTemp.get(); - - totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); - totalPoreVol = subRegionTotalPoreVol.get(); - totalMass = subRegionTotalMass.get(); - } -}; - - -/******************************** HydrostaticPressureKernel ********************************/ - -struct HydrostaticPressureKernel -{ - - template< typename FLUID_WRAPPER > - static bool - computeHydrostaticPressure( integer const maxNumEquilIterations, - real64 const & equilTolerance, - real64 const (&gravVector)[ 3 ], - FLUID_WRAPPER fluidWrapper, - real64 const & refElevation, - real64 const & refPres, - real64 const & refDens, - real64 const & newElevation, - real64 & newPres, - real64 & newDens ) - { - // Step 1: guess the pressure with the refDensity - - real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); - real64 pres0 = refPres - refDens * gravCoef; - real64 pres1 = 0.0; - - // Step 2: compute the mass density at this elevation using the guess, and update pressure - - real64 dens = 0.0; - real64 visc = 0.0; - constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, - pres0, - dens, - visc ); - pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; - - // Step 3: fixed-point iteration until convergence - - bool equilHasConverged = false; - for( localIndex eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) - { - - // check convergence - equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); - pres0 = pres1; - - // if converged, move on - if( equilHasConverged ) - { - break; - } - - // compute the density at this elevation using the previous pressure, and compute the new pressure - constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, - pres0, - dens, - visc ); - pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; - } - - // Step 4: save the hydrostatic pressure and the corresponding density - - newPres = pres1; - newDens = dens; - - return equilHasConverged; - } - - - template< typename FLUID_WRAPPER > - static bool - launch( localIndex const size, - integer const maxNumEquilIterations, - real64 const equilTolerance, - real64 const (&gravVector)[ 3 ], - real64 const & minElevation, - real64 const & elevationIncrement, - real64 const & datumElevation, - real64 const & datumPres, - FLUID_WRAPPER fluidWrapper, - arrayView1d< arrayView1d< real64 > const > elevationValues, - arrayView1d< real64 > pressureValues ) - { - bool hasConverged = true; - - // Step 1: compute the mass density at the datum elevation - - real64 datumDens = 0.0; - real64 datumVisc = 0.0; - - constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, - datumPres, - datumDens, - datumVisc ); - - // Step 2: find the closest elevation to datumElevation - - forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) - { - real64 const elevation = minElevation + i * elevationIncrement; - elevationValues[0][i] = elevation; - } ); - integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), - elevationValues[0].size(), - datumElevation ); - - - // Step 3: compute the mass density and pressure at the reference elevation - - array1d< real64 > dens( pressureValues.size() ); - - bool const hasConvergedRef = - computeHydrostaticPressure( maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - datumElevation, - datumPres, - datumDens, - elevationValues[0][iRef], - pressureValues[iRef], - dens[iRef] ); - if( !hasConvergedRef ) - { - return false; - } - - - // Step 4: for each elevation above the reference elevation, compute the pressure - - localIndex const numEntriesAboveRef = size - iRef - 1; - forAll< serialPolicy >( numEntriesAboveRef, [=, &hasConverged] ( localIndex const i ) - { - bool const hasConvergedAboveRef = - computeHydrostaticPressure( maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - elevationValues[0][iRef+i], - pressureValues[iRef+i], - dens[iRef+i], - elevationValues[0][iRef+i+1], - pressureValues[iRef+i+1], - dens[iRef+i+1] ); - if( !hasConvergedAboveRef ) - { - hasConverged = false; - } - - - } ); - - // Step 5: for each elevation below the reference elevation, compute the pressure - - localIndex const numEntriesBelowRef = iRef; - forAll< serialPolicy >( numEntriesBelowRef, [=, &hasConverged] ( localIndex const i ) - { - bool const hasConvergedBelowRef = - computeHydrostaticPressure( maxNumEquilIterations, - equilTolerance, - gravVector, - fluidWrapper, - elevationValues[0][iRef-i], - pressureValues[iRef-i], - dens[iRef-i], - elevationValues[0][iRef-i-1], - pressureValues[iRef-i-1], - dens[iRef-i-1] ); - if( !hasConvergedBelowRef ) - { - hasConverged = false; - } - } ); - - return hasConverged; - } -}; - - -} // namespace singlePhaseBaseKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp deleted file mode 100644 index cd1e04516c1..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp +++ /dev/null @@ -1,962 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file SinglePhaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEFVMKERNELS_HPP - -#include "common/DataLayouts.hpp" -#include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" -#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" -#include "constitutive/fluid/singlefluid/SlurryFluidBase.hpp" -#include "constitutive/fluid/singlefluid/SlurryFluidFields.hpp" -#include "constitutive/permeability/PermeabilityBase.hpp" -#include "constitutive/permeability/PermeabilityFields.hpp" -#include "fieldSpecification/AquiferBoundaryCondition.hpp" -#include "finiteVolume/BoundaryStencil.hpp" -#include "finiteVolume/FluxApproximationBase.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" -#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp" -#include "codingUtilities/Utilities.hpp" - -namespace geos -{ - -namespace singlePhaseFVMKernels -{ - -/******************************** FaceBasedAssemblyKernelBase ********************************/ - -/** - * @brief Base class for FaceBasedAssemblyKernel that holds all data not dependent - * on template parameters (like stencil type and number of dofs). - */ -class FaceBasedAssemblyKernelBase -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; - - using SinglePhaseFlowAccessors = - StencilAccessors< fields::ghostRank, - fields::flow::pressure, - fields::flow::pressure_n, - fields::flow::gravityCoefficient, - fields::flow::mobility, - fields::flow::dMobility_dPressure >; - - using SinglePhaseFluidAccessors = - StencilMaterialAccessors< constitutive::SingleFluidBase, - fields::singlefluid::density, - fields::singlefluid::dDensity_dPressure >; - - using SlurryFluidAccessors = - StencilMaterialAccessors< constitutive::SlurryFluidBase, - fields::singlefluid::density, - fields::singlefluid::dDensity_dPressure >; - - using PermeabilityAccessors = - StencilMaterialAccessors< constitutive::PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure >; - - using ProppantPermeabilityAccessors = - StencilMaterialAccessors< constitutive::PermeabilityBase, - fields::permeability::permeability, - fields::permeability::dPerm_dPressure, - fields::permeability::dPerm_dDispJump, - fields::permeability::permeabilityMultiplier >; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofNumberAccessor accessor for the dof numbers - * @param[in] singleFlowAccessors accessor for wrappers registered by the solver - * @param[in] singlePhaseFluidAccessors accessor for wrappers registered by the singlefluid model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - FaceBasedAssemblyKernelBase( globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : m_rankOffset( rankOffset ), - m_dt( dt ), - m_dofNumber( dofNumberAccessor.toNestedViewConst() ), - m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), - m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), - m_ghostRank( singlePhaseFlowAccessors.get( fields::ghostRank {} ) ), - m_gravCoef( singlePhaseFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), - m_pres( singlePhaseFlowAccessors.get( fields::flow::pressure {} ) ), - m_mob( singlePhaseFlowAccessors.get( fields::flow::mobility {} ) ), - m_dMob_dPres( singlePhaseFlowAccessors.get( fields::flow::dMobility_dPressure {} ) ), - m_dens( singlePhaseFluidAccessors.get( fields::singlefluid::density {} ) ), - m_dDens_dPres( singlePhaseFluidAccessors.get( fields::singlefluid::dDensity_dPressure {} ) ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ) - {} - -protected: - - /// Offset for my MPI rank - globalIndex const m_rankOffset; - - /// Time step size - real64 const m_dt; - - /// Views on dof numbers - ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; - - /// Views on permeability - ElementViewConst< arrayView3d< real64 const > > m_permeability; - ElementViewConst< arrayView3d< real64 const > > m_dPerm_dPres; - - /// Views on ghost rank numbers and gravity coefficients - ElementViewConst< arrayView1d< integer const > > const m_ghostRank; - ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; - - // Primary and secondary variables - /// Views on pressure - ElementViewConst< arrayView1d< real64 const > > const m_pres; - - /// Views on fluid mobility - ElementViewConst< arrayView1d< real64 const > > const m_mob; - ElementViewConst< arrayView1d< real64 const > > const m_dMob_dPres; - - /// Views on fluid density - ElementViewConst< arrayView2d< real64 const > > const m_dens; - ElementViewConst< arrayView2d< real64 const > > const m_dDens_dPres; - - // Residual and jacobian - - /// View on the local CRS matrix - CRSMatrixView< real64, globalIndex const > const m_localMatrix; - /// View on the local RHS - arrayView1d< real64 > const m_localRhs; -}; - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase -{ -public: - - /// 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_EQN; - - /// Maximum number of elements at the face - static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; - - /// Maximum number of connections at the face - static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; - - /// Maximum number of points in the stencil - static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; - - /** - * @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] singlePhaseFlowAccessors - * @param[in] singlePhaseFluidAccessors - * @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 - */ - FaceBasedAssemblyKernel( globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : FaceBasedAssemblyKernelBase( rankOffset, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ), - m_stencilWrapper( stencilWrapper ), - m_seri( stencilWrapper.getElementRegionIndices() ), - m_sesri( stencilWrapper.getElementSubRegionIndices() ), - m_sei( stencilWrapper.getElementIndices() ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - 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, localIndex numElems ) - : stencilSize( size ), - numFluxElems( numElems ), - dofColIndices( size * numDof ), - localFlux( numElems * numEqn ), - localFluxJacobian( numElems * numEqn, size * numDof ) - {} - - // Stencil information - - /// Stencil size for a given connection - localIndex const stencilSize; - - /// Number of elements for a given connection - localIndex const numFluxElems; - - // Transmissibility and derivatives - - /// Transmissibility - real64 transmissibility[maxNumConns][2]{}; - /// Derivatives of transmissibility with respect to pressure - real64 dTrans_dPres[maxNumConns][2]{}; - - // 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 equations except volume balance) - stackArray1d< real64, maxNumElems * numEqn > localFlux; - /// Storage for the face local Jacobian matrix - stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; - - }; - - /** - * @brief Getter for the stencil size at this connection - * @param[in] iconn the connection index - * @return the size of the stencil at this connection - */ - GEOS_HOST_DEVICE - localIndex stencilSize( localIndex const iconn ) const - { return m_sei[iconn].size(); } - - /** - * @brief Getter for the number of elements at this connection - * @param[in] iconn the connection index - * @return the number of elements at this connection - */ - GEOS_HOST_DEVICE - localIndex numPointsInFlux( localIndex const iconn ) const - { return m_stencilWrapper.numPointsInFlux( iconn ); } - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const iconn, - StackVariables & stack ) const - { - // set degrees of freedom indices for this face - for( integer i = 0; i < stack.stencilSize; ++i ) - { - globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[i * numDof + jdof] = offset + 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 flux - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] NoOpFunc the function used to customize the computation of the flux - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - // first, compute the transmissibilities at this face - m_stencilWrapper.computeWeights( iconn, - m_permeability, - m_dPerm_dPres, - stack.transmissibility, - stack.dTrans_dPres ); - - localIndex k[2]; - localIndex connectionIndex = 0; - - for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] ) - { - real64 fluxVal = 0.0; - real64 dFlux_dTrans = 0.0; - real64 alpha = 0.0; - real64 mobility = 0.0; - real64 potGrad = 0.0; - real64 trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] }; - real64 dTrans[2] = { stack.dTrans_dPres[connectionIndex][0], stack.dTrans_dPres[connectionIndex][1] }; - real64 dFlux_dP[2] = {0.0, 0.0}; - localIndex const regionIndex[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const subRegionIndex[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const elementIndex[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - fluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, - trans, - dTrans, - m_pres, - m_gravCoef, - m_dens, - m_dDens_dPres, - m_mob, - m_dMob_dPres, - alpha, - mobility, - potGrad, - fluxVal, - dFlux_dP, - dFlux_dTrans ); - - // populate local flux vector and derivatives - stack.localFlux[k[0]*numEqn] += m_dt * fluxVal; - stack.localFlux[k[1]*numEqn] -= m_dt * fluxVal; - - for( integer ke = 0; ke < 2; ++ke ) - { - localIndex const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[k[0]*numEqn][localDofIndexPres] += m_dt * dFlux_dP[ke]; - stack.localFluxJacobian[k[1]*numEqn][localDofIndexPres] -= m_dt * dFlux_dP[ke]; - } - - // Customize the kernel with this lambda - kernelOp( k, regionIndex, subRegionIndex, elementIndex, connectionIndex, alpha, mobility, potGrad, fluxVal, dFlux_dP ); - - connectionIndex++; - } - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && kernelOp = NoOpFunc{} ) const - { - // add contribution to residual and jacobian into: - // - the mass balance equation - // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels - for( integer i = 0; i < stack.numFluxElems; ++i ) - { - if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) - { - globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow ); - - RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow], stack.localFlux[i * numEqn] ); - m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn].dataIfContiguous(), - stack.stencilSize * numDof ); - - // call the lambda to assemble additional terms, such as thermal terms - kernelOp( i, localRow ); - } - } - } - - /** - * @brief Performs the kernel launch - * @tparam POLICY the policy used in the RAJA kernels - * @tparam KERNEL_TYPE the kernel type - * @param[in] numConnections the number of connections - * @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 numConnections, - KERNEL_TYPE const & kernelComponent ) - { - GEOS_MARK_FUNCTION; - - forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), - kernelComponent.numPointsInFlux( iconn ) ); - - kernelComponent.setup( iconn, stack ); - kernelComponent.computeFlux( iconn, stack ); - kernelComponent.complete( iconn, stack ); - } ); - } - - -protected: - - // Stencil information - - /// Reference to the stencil wrapper - STENCILWRAPPER const m_stencilWrapper; - - /// Connection to element maps - typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; - typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @param[in] rankOffset the offset of my MPI rank - * @param[in] dofKey string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( globalIndex const rankOffset, - string const & dofKey, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_EQN = 1; - integer constexpr NUM_DOF = 1; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - using kernelType = FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; - typename kernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName ); - typename kernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permAccessors( elemManager, solverName ); - - kernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor, - flowAccessors, fluidAccessors, permAccessors, - dt, localMatrix, localRhs ); - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } -}; - -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichFaceBasedAssemblyKernel - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, - BoundaryStencilWrapper > -{ -public: - - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; - using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_ghostRank; - using AbstractBase::m_gravCoef; - using AbstractBase::m_pres; - using AbstractBase::m_mob; - using AbstractBase::m_dMob_dPres; - using AbstractBase::m_dens; - using AbstractBase::m_dDens_dPres; - using AbstractBase::m_permeability; - using AbstractBase::m_dPerm_dPres; - - using AbstractBase::m_localMatrix; - using AbstractBase::m_localRhs; - - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, - BoundaryStencilWrapper >; - using Base::numDof; - using Base::numEqn; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of my MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid wrapper - * @param[in] dofNumberAccessor - * @param[in] singlePhaseFlowAccessors - * @param[in] singlePhaseFluidAccessors - * @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 - */ - DirichletFaceBasedAssemblyKernel( globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, - stencilWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ), - m_facePres( faceManager.getField< fields::flow::facePressure >() ), - m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), - m_fluidWrapper( fluidWrapper ) - {} - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - 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 GEOS_UNUSED_PARAM( size ), - localIndex GEOS_UNUSED_PARAM( numElems ) ) - {} - - /// Transmissibility - real64 transmissibility = 0.0; - - /// Indices of the matrix rows/columns corresponding to the dofs in this face - globalIndex dofColIndices[numDof]{}; - - /// Storage for the face local residual - real64 localFlux[numEqn]{}; - - /// Storage for the face local Jacobian - real64 localFluxJacobian[numEqn][numDof]{}; - - }; - - - /** - * @brief Performs the setup phase for the kernel. - * @param[in] iconn the connection index - * @param[in] stack the stack variables - */ - GEOS_HOST_DEVICE - void setup( localIndex const iconn, - StackVariables & stack ) const - { - globalIndex const offset = - m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; - - for( integer jdof = 0; jdof < numDof; ++jdof ) - { - stack.dofColIndices[jdof] = offset + jdof; - } - } - - /** - * @brief Compute the local Dirichlet face 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] iconn the connection 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 - void computeFlux( localIndex const iconn, - StackVariables & stack, - FUNC && compFluxKernelOp = NoOpFunc{} ) const - { - using Order = BoundaryStencil::Order; - localIndex constexpr numElems = BoundaryStencil::maxNumPointsInFlux; - - stackArray1d< real64, numElems > mobility( numElems ); - stackArray1d< real64, numElems > dMobility_dP( numElems ); - - localIndex const er = m_seri( iconn, Order::ELEM ); - localIndex const esr = m_sesri( iconn, Order::ELEM ); - localIndex const ei = m_sei( iconn, Order::ELEM ); - localIndex const kf = m_sei( iconn, Order::FACE ); - - // Get flow quantities on the elem/face - real64 faceDens, faceVisc; - constitutive::SingleFluidBaseUpdate::computeValues( m_fluidWrapper, m_facePres[kf], faceDens, faceVisc ); - - mobility[Order::ELEM] = m_mob[er][esr][ei]; - singlePhaseBaseKernels::MobilityKernel::compute( faceDens, faceVisc, mobility[Order::FACE] ); - - dMobility_dP[Order::ELEM] = m_dMob_dPres[er][esr][ei]; - dMobility_dP[Order::FACE] = 0.0; - - // Compute average density - real64 const densMean = 0.5 * ( m_dens[er][esr][ei][0] + faceDens ); - real64 const dDens_dP = 0.5 * m_dDens_dPres[er][esr][ei][0]; - - // Evaluate potential difference - real64 const potDif = (m_pres[er][esr][ei] - m_facePres[kf]) - - densMean * (m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]); - real64 const dPotDif_dP = 1.0 - dDens_dP * m_gravCoef[er][esr][ei]; - - real64 dTrans_dPerm[3]; - m_stencilWrapper.computeWeights( iconn, m_permeability, stack.transmissibility, dTrans_dPerm ); - real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); - - real64 const f = stack.transmissibility * potDif; - real64 const dF_dP = stack.transmissibility * dPotDif_dP + dTrans_dPres * potDif; - - // Upwind mobility - localIndex const k_up = ( potDif >= 0 ) ? Order::ELEM : Order::FACE; - real64 const mobility_up = mobility[k_up]; - real64 const dMobility_dP_up = dMobility_dP[k_up]; - - // call the lambda in the phase loop to allow the reuse of the fluxes and their derivatives - // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase - - compFluxKernelOp( er, esr, ei, kf, f, dF_dP, mobility_up, dMobility_dP_up ); - - // *** end of upwinding - - // Populate local flux vector and derivatives - - stack.localFlux[0] = m_dt * mobility[k_up] * f; - stack.localFluxJacobian[0][0] = m_dt * ( mobility_up * dF_dP + dMobility_dP_up * f ); - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - template< typename FUNC = NoOpFunc > - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack, - FUNC && assemblyKernelOp = NoOpFunc{} ) const - { - using Order = BoundaryStencil::Order; - - localIndex const er = m_seri( iconn, Order::ELEM ); - localIndex const esr = m_sesri( iconn, Order::ELEM ); - localIndex const ei = m_sei( iconn, Order::ELEM ); - - if( m_ghostRank[er][esr][ei] < 0 ) - { - // Add to global residual/jacobian - globalIndex const dofIndex = m_dofNumber[er][esr][ei]; - localIndex const localRow = LvArray::integerConversion< localIndex >( dofIndex - m_rankOffset ); - - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow], stack.localFlux[0] ); - - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow, - stack.dofColIndices, - stack.localFluxJacobian[0], - numDof ); - - assemblyKernelOp( localRow ); - } - } - -protected: - - /// Views on face pressure, temperature, and composition - arrayView1d< real64 const > const m_facePres; - - /// View on the face gravity coefficient - arrayView1d< real64 const > const m_faceGravCoef; - - /// Reference to the fluid wrapper - FLUIDWRAPPER const m_fluidWrapper; - -}; - - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -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 string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the boundary stencil wrapper - * @param[in] fluidBase the single phase fluid constitutive model - * @param[in] dt time step size - * @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, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - BoundaryStencilWrapper const & stencilWrapper, - constitutive::SingleFluidBase & fluidBase, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); - - integer constexpr NUM_DOF = 1; - integer constexpr NUM_EQN = 1; - using kernelType = DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); - typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - - kernelType kernel( rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ); - - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } - -}; - - -/******************************** AquiferBCKernel ********************************/ - -/** - * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian - */ -struct AquiferBCKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - GEOS_HOST_DEVICE - static void - compute( real64 const & aquiferVolFlux, - real64 const & dAquiferVolFlux_dPres, - real64 const & aquiferDens, - real64 const & dens, - real64 const & dDens_dPres, - real64 const & dt, - real64 & localFlux, - real64 & localFluxJacobian ) - { - if( aquiferVolFlux > 0 ) // aquifer is upstream - { - localFlux -= dt * aquiferVolFlux * aquiferDens; - localFluxJacobian -= dt * dAquiferVolFlux_dPres * aquiferDens; - } - else // reservoir is upstream - { - localFlux -= dt * aquiferVolFlux * dens; - localFluxJacobian -= dt * (dAquiferVolFlux_dPres * dens + aquiferVolFlux * dDens_dPres); - } - } - - static void - launch( BoundaryStencil const & stencil, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - real64 const & aquiferDens, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & pres_n, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const > > const & dens, - ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, - real64 const & timeAtBeginningOfStep, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - using Order = BoundaryStencil::Order; - - BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); - BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); - - forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - // working variables - real64 localFlux = 0.0; - real64 localFluxJacobian = 0.0; - - localIndex const er = seri( iconn, Order::ELEM ); - localIndex const esr = sesri( iconn, Order::ELEM ); - localIndex const ei = sefi( iconn, Order::ELEM ); - real64 const areaFraction = weight( iconn, Order::ELEM ); - - // compute the aquifer influx rate using the pressure influence function and the aquifer props - real64 dAquiferVolFlux_dPres = 0.0; - real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, - dt, - pres[er][esr][ei], - pres_n[er][esr][ei], - gravCoef[er][esr][ei], - areaFraction, - dAquiferVolFlux_dPres ); - - // compute the phase/component aquifer flux - AquiferBCKernel::compute( aquiferVolFlux, - dAquiferVolFlux_dPres, - aquiferDens, - dens[er][esr][ei][0], - dDens_dPres[er][esr][ei][0], - dt, - localFlux, - localFluxJacobian ); - - // Add to residual/jacobian - if( ghostRank[er][esr][ei] < 0 ) - { - globalIndex const globalRow = dofNumber[er][esr][ei]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( localMatrix.numRows(), localRow ); - - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow], localFlux ); - localMatrix.addToRow< parallelDeviceAtomic >( localRow, - &dofNumber[er][esr][ei], - &localFluxJacobian, - 1 ); - } - } ); - } - -}; - - -} // namespace singlePhaseFVMKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp new file mode 100644 index 00000000000..d61b9d379dd --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/StencilWeightsUpdateKernel.hpp @@ -0,0 +1,79 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StencilWeightsUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_STENCILWEIGHTSUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_STENCILWEIGHTSUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "mesh/ElementRegionManager.hpp" + +namespace geos +{ + +namespace flowSolverBaseKernels +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +/** + * @brief + * + * @tparam STENCILWRAPPER + */ +template< typename STENCILWRAPPER > +struct stencilWeightsUpdateKernel +{ + /** + * @brief + * + * @param stencilWrappper + * @param hydraulicAperture + */ + inline static void prepareStencilWeights( STENCILWRAPPER & stencilWrapper, + ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) + { + forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + stencilWrapper.removeHydraulicApertureContribution( iconn, hydraulicAperture ); + } ); + } + + /** + * @brief + * + * @param stencilWrappper + * @param hydraulicAperture + */ + inline static void updateStencilWeights( STENCILWRAPPER & stencilWrapper, + ElementViewConst< arrayView1d< real64 const > > const hydraulicAperture ) + { + forAll< parallelDevicePolicy<> >( stencilWrapper.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + stencilWrapper.addHydraulicApertureContribution( iconn, hydraulicAperture ); + } ); + } +}; + +} // namespace flowSolverBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_STENCILWEIGHTSUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseBaseKernels.hpp deleted file mode 100644 index 717ff1a3e60..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseBaseKernels.hpp +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ThermalCompositionalMultiphaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP - -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" - -namespace geos -{ - -namespace thermalCompositionalMultiphaseBaseKernels -{ - - -/******************************** PhaseVolumeFractionKernel ********************************/ - -/** - * @class PhaseVolumeFractionKernel - * @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 phase volume fractions - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseVolumeFractionKernel : public isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE > -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE >; - using Base::m_dPhaseDens; - using Base::m_dPhaseFrac; - using Base::m_dPhaseVolFrac; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - */ - PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid ) - : Base( subRegion, fluid ) - {} - - /** - * @brief Compute the phase volume fractions in an element - * @param[in] ei the element index - */ - GEOS_HOST_DEVICE - real64 compute( localIndex const ei ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; - - arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - // Call the base compute the compute the phase volume fraction - return Base::compute( ei, [&] ( localIndex const ip, - real64 const & phaseVolFrac, - real64 const & phaseDensInv, - real64 const & totalDensity ) - { - // when this lambda is called, we are in the phase loop - // for each phase ip, compute the derivative of phase volume fraction wrt temperature - dPhaseVolFrac[ip][Deriv::dT] = (dPhaseFrac[ip][Deriv::dT] - phaseVolFrac * dPhaseDens[ip][Deriv::dT]) * phaseDensInv; - dPhaseVolFrac[ip][Deriv::dT] *= totalDensity; - } ); - } - -}; - -/** - * @class PhaseVolumeFractionKernelFactory - */ -class PhaseVolumeFractionKernelFactory -{ -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 real64 - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid ) - { - real64 maxDeltaPhaseVolFrac = 0.0; - if( numPhase == 2 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); - maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - return maxDeltaPhaseVolFrac; - } -}; - - -/******************************** 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< localIndex NUM_COMP, localIndex NUM_DOF > -class ElementBasedAssemblyKernel : public isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::m_numPhases; - using Base::m_rankOffset; - using Base::m_dofNumber; - using Base::m_elemGhostRank; - using Base::m_volume; - using Base::m_porosity; - using Base::m_dPoro_dPres; - using Base::m_dCompFrac_dCompDens; - using Base::m_phaseVolFrac; - using Base::m_dPhaseVolFrac; - using Base::m_phaseDens; - using Base::m_dPhaseDens; - using Base::m_phaseCompFrac; - using Base::m_dPhaseCompFrac; - using Base::m_localMatrix; - using Base::m_localRhs; - - /** - * @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, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) - : Base( numPhases, rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs, kernelFlags ), - m_dPoro_dTemp( solid.getDporosity_dTemperature() ), - m_phaseInternalEnergy( fluid.phaseInternalEnergy() ), - m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy() ), - m_rockInternalEnergy( solid.getInternalEnergy() ), - m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ), - m_energy_n( subRegion.getField< fields::flow::energy_n >() ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables() - : Base::StackVariables() - {} - - using Base::StackVariables::localRow; - using Base::StackVariables::dofIndices; - using Base::StackVariables::localResidual; - using Base::StackVariables::localJacobian; - - // derivative of pore volume wrt temperature - real64 dPoreVolume_dTemp = 0.0; - - // Solid energy - - /// Solid energy at time n+1 - real64 solidEnergy = 0.0; - - /// Derivative of solid internal energy with respect to pressure - real64 dSolidEnergy_dPres = 0.0; - - /// Derivative of solid internal energy with respect to temperature - real64 dSolidEnergy_dTemp = 0.0; - - }; - - /** - * @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 ); - - // derivative of pore volume wrt temperature - stack.dPoreVolume_dTemp = m_volume[ei] * m_dPoro_dTemp[ei][0]; - - // initialize the solid volume - real64 const solidVolume = m_volume[ei] * ( 1.0 - m_porosity[ei][0] ); - real64 const dSolidVolume_dPres = -m_volume[ei] * m_dPoro_dPres[ei][0]; - real64 const dSolidVolume_dTemp = -stack.dPoreVolume_dTemp; - - // initialize the solid internal energy - stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; - stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; - stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] - + dSolidVolume_dTemp * m_rockInternalEnergy[ei][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 - */ - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - StackVariables & stack ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - // start with old time step value - stack.localResidual[numEqn-1] = -m_energy_n[ei]; - - Base::computeAccumulation( ei, stack, [&] ( integer const ip, - real64 const & phaseAmount, - 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, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; - arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; - arraySlice2d< real64 const, constitutive::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.dPoreVolume_dTemp * phaseVolFrac[ip] * phaseDens[ip] - + stack.poreVolume * (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 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; - - // 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; - } - } ); - - // Step 3: assemble the solid part of the accumulation term - - // local accumulation and derivatives w.r.t. pressure and temperature - stack.localResidual[numEqn-1] += stack.solidEnergy; - stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; - stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; - - } - - /** - * @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 = constitutive::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< serialAtomic >( stack.localRow + numEqn-1, - stack.dofIndices, - stack.localJacobian[numEqn-1], - numDof ); - } - -protected: - - /// View on derivative of porosity w.r.t temperature - arrayView2d< real64 const > const m_dPoro_dTemp; - - /// Views on phase internal energy - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseInternalEnergy; - arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy; - - /// Views on rock internal energy - arrayView2d< real64 const > m_rockInternalEnergy; - arrayView2d< real64 const > m_dRockInternalEnergy_dTemp; - - /// Views on energy - arrayView1d< real64 const > m_energy_n; - -}; - -/** - * @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[in] solid the solid 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, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - 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, solid, localMatrix, localRhs, kernelFlags ); - ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP, NUM_DOF > >( subRegion.size(), kernel ); - } ); - } - -}; - -/******************************** FluidUpdateKernel ********************************/ - -struct FluidUpdateKernel -{ - template< typename POLICY, typename FLUID_WRAPPER > - static void - launch( localIndex const size, - FLUID_WRAPPER const & fluidWrapper, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & temp, - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) - { - fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); - } - } ); - } - - template< typename POLICY, typename FLUID_WRAPPER > - static void - launch( SortedArrayView< localIndex const > const & targetSet, - FLUID_WRAPPER const & fluidWrapper, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & temp, - arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) - { - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - localIndex const k = targetSet[a]; - for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) - { - fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); - } - } ); - } -}; - -/******************************** SolidInternalEnergyUpdateKernel ********************************/ - -struct SolidInternalEnergyUpdateKernel -{ - - template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > - static void - launch( localIndex const size, - SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, - arrayView1d< real64 const > const & temp ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - solidInternalEnergyWrapper.update( k, temp[k] ); - } ); - } -}; - -/******************************** ScalingForSystemSolutionKernel ********************************/ - -/** - * @class ScalingForSystemSolutionKernel - * @brief Define the kernel for scaling the Newton update - */ -class ScalingForSystemSolutionKernel : public isothermalCompositionalMultiphaseBaseKernels::ScalingForSystemSolutionKernel -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::ScalingForSystemSolutionKernel; - using Base::m_numComp; - using Base::m_localSolution; - - /** - * @brief Create a new kernel instance - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxAbsolutePresChange the max allowed absolute pressure change - * @param[in] maxRelativeTempChange the max allowed relative temperature change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] maxRelativeCompDensChange the max allowed comp density change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] temperature the temperature vector - * @param[in] compDens the component density vector - * @param[in] pressureScalingFactor the pressure local scaling factor - * @param[in] compDensScalingFactor the component density local scaling factor - * @param[in] temperatureFactor the temperature local scaling factor - */ - ScalingForSystemSolutionKernel( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxRelativeTempChange, - real64 const maxCompFracChange, - real64 const maxRelativeCompDensChange, - 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, - integer const temperatureOffset ) - : Base( maxRelativePresChange, - maxAbsolutePresChange, - maxCompFracChange, - maxRelativeCompDensChange, - rankOffset, - numComp, - dofKey, - subRegion, - localSolution, - pressure, - compDens, - pressureScalingFactor, - compDensScalingFactor ), - m_maxRelativeTempChange( maxRelativeTempChange ), - m_temperature( temperature ), - m_temperatureScalingFactor( temperatureScalingFactor ), - m_temperatureOffset( temperatureOffset ) - {} - - /** - * @brief Compute the local value - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void compute( localIndex const ei, - StackVariables & stack ) const - { - computeScalingFactor( ei, stack ); - } - - /** - * @brief Compute the local value of the scaling factor - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeScalingFactor( localIndex const ei, - StackVariables & stack ) const - { - real64 constexpr eps = isothermalCompositionalMultiphaseBaseKernels::minDensForDivision; - Base::computeScalingFactor( ei, stack, [&] () - { - // compute the change in temperature - real64 const temp = m_temperature[ei]; - real64 const absTempChange = LvArray::math::abs( m_localSolution[stack.localRow + m_temperatureOffset] ); - if( stack.localMaxDeltaTemp < absTempChange ) - { - stack.localMaxDeltaTemp = absTempChange; - } - - m_temperatureScalingFactor[ei] = 1.0; - - if( temp > eps ) - { - real64 const relativeTempChange = absTempChange / temp; - if( relativeTempChange > m_maxRelativeTempChange ) - { - real64 const tempScalingFactor = m_maxRelativeTempChange / relativeTempChange; - m_temperatureScalingFactor[ei] = tempScalingFactor; - if( stack.localMinVal > tempScalingFactor ) - { - stack.localMinVal = tempScalingFactor; - } - if( stack.localMinTempScalingFactor > tempScalingFactor ) - { - stack.localMinTempScalingFactor = tempScalingFactor; - } - } - } - } ); - } - -protected: - - /// Max allowed changes in primary variables - real64 const m_maxRelativeTempChange; - - /// View on the primary variables - arrayView1d< real64 const > const m_temperature; - - /// View on the scaling factor - arrayView1d< real64 > const m_temperatureScalingFactor; - - /// Temperature offset in solution array - integer const m_temperatureOffset; - -}; - -/** - * @class ScalingForSystemSolutionKernelFactory - */ - -class ScalingForSystemSolutionKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxAbsolutePresChange the max allowed absolute pressure change - * @param[in] maxRelativeTempChange the max allowed relative temperature change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] maxRelativeCompdensChange the max allowed relative component density change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static ScalingForSystemSolutionKernel::StackVariables - createAndLaunch( real64 const maxRelativePresChange, - real64 const maxAbsolutePresChange, - real64 const maxRelativeTempChange, - real64 const maxCompFracChange, - real64 const maxRelativeCompDensChange, - 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, - integer const temperatureOffset ) - { - - ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxRelativeTempChange, - maxCompFracChange, maxRelativeCompDensChange, - rankOffset, numComp, dofKey, subRegion, localSolution, - pressure, temperature, compDens, pressureScalingFactor, - compDensScalingFactor, temperatureScalingFactor, temperatureOffset ); - return thermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - -/******************************** SolutionCheckKernel ********************************/ - -/** - * @class SolutionCheckKernel - * @brief Define the kernel for checking the updated solution - */ -class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel -{ -public: - - using Base = isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel; - using Base::m_numComp; - using Base::m_localSolution; - using Base::m_scalingFactor; - - static real64 constexpr minTemperature = constants::zeroDegreesCelsiusInKelvin; - - /** - * @brief Create a new kernel instance - * @param[in] allowCompDensChopping flag to allow the component density chopping - * @param[in] scalingFactor the scaling factor - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - * @param[in] pressure the pressure vector - * @param[in] temperature the temperature vector - * @param[in] compDens the component density vector - */ - SolutionCheckKernel( integer const allowCompDensChopping, - 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 > compDensScalingFactor, - 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 ), - m_temperature( temperature ), - m_temperatureScalingFactor( temperatureScalingFactor ), - m_temperatureOffset( temperatureOffset ) - {} - - /** - * @brief Compute the local value of the solution check - * @param[in] ei the element index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeSolutionCheck( localIndex const ei, - StackVariables & stack ) const - { - Base::computeSolutionCheck( ei, stack, [&] () - { - 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_temperatureOffset]); - if( newTemp < minTemperature ) - { - stack.localMinVal = 0; - } - } ); - } - -protected: - - /// View on the primary variables - arrayView1d< real64 const > const m_temperature; - - /// View on the scaling factor - arrayView1d< real64 const > const m_temperatureScalingFactor; - - /// Offset to temperature variable - integer m_temperatureOffset; - -}; - -/** - * @class SolutionCheckKernelFactory - */ -class SolutionCheckKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] maxRelativePresChange the max allowed relative pressure change - * @param[in] maxRelativeTempChange the max allowed relative temperature change - * @param[in] maxCompFracChange the max allowed comp fraction change - * @param[in] rankOffset the rank offset - * @param[in] numComp the number of components - * @param[in] dofKey the dof key to get dof numbers - * @param[in] subRegion the subRegion - * @param[in] localSolution the Newton update - */ - template< typename POLICY > - static SolutionCheckKernel::StackVariables - createAndLaunch( integer const allowCompDensChopping, - 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, - integer temperatureOffset ) - { - - SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, - pressure, temperature, compDens, pressureScalingFactor, compDensScalingFactor, temperatureScalingFactor, - rankOffset, numComp, dofKey, subRegion, localSolution, - temperatureOffset ); - return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); - } - -}; - - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 3 > -{ -public: - - using Base = ResidualNormKernelBase< 3 >; - 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 numComponents, - integer const numPhases, - ElementSubRegionBase const & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - constitutive::SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_numComponents( numComponents ), - m_numPhases( numPhases ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_phaseVolFrac_n( subRegion.getField< fields::flow::phaseVolumeFraction_n >() ), - m_totalDens_n( fluid.totalDensity_n() ), - m_phaseDens_n( fluid.phaseDensity_n() ), - m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() ), - m_solidInternalEnergy_n( solidInternalEnergy.getInternalEnergy_n() ) - {} - - GEOS_HOST_DEVICE - void computeMassEnergyNormalizers( localIndex const ei, - real64 & massNormalizer, - real64 & energyNormalizer ) const - { - massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - real64 const poreVolume = m_porosity_n[ei][0] * m_volume[ei]; - energyNormalizer = m_solidInternalEnergy_n[ei][0] * ( 1.0 - m_porosity_n[ei][0] ) * m_volume[ei]; - for( integer ip = 0; ip < m_numPhases; ++ip ) - { - energyNormalizer += m_phaseInternalEnergy_n[ei][0][ip] * m_phaseDens_n[ei][0][ip] * m_phaseVolFrac_n[ei][ip] * poreVolume; - } - // warning: internal energy can be negative - energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( energyNormalizer ) ); - } - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); - - // step 1: mass residual - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - } - - // step 2: volume residual - - real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; - if( valVol > stack.localValue[1] ) - { - stack.localValue[1] = valVol; - } - - // step 3: energy residual - - real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents + 1] ) / energyNormalizer; - if( valEnergy > stack.localValue[2] ) - { - stack.localValue[2] = valEnergy; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - // note: for the L2 norm, we bundle the volume and mass residuals/normalizers - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - - // step 1: mass residual - - for( integer idof = 0; idof < m_numComponents; ++idof ) - { - stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; - stack.localNormalizer[0] += massNormalizer; - } - - // step 2: volume residual - - real64 const valVol = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the - // multiplication - stack.localValue[1] += valVol * valVol; - stack.localNormalizer[1] += massNormalizer; - - // step 3: energy residual - - stack.localValue[2] += m_localResidual[stack.localRow + m_numComponents + 1] * m_localResidual[stack.localRow + m_numComponents + 1]; - stack.localNormalizer[2] += energyNormalizer; - } - -protected: - - /// Number of fluid components - integer const m_numComponents; - - /// Number of fluid phases - integer const m_numPhases; - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on porosity at the previous converged time step - arrayView2d< real64 const > const m_porosity_n; - - /// View on phase properties at the previous converged time step - arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac_n; - arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const m_totalDens_n; - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens_n; - arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseInternalEnergy_n; - - /// View on solid properties at the previous converged time step - arrayView2d< real64 const > const m_solidInternalEnergy_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @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] localResidual the residual vector on my MPI rank - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[in] solidInternalEnergy the solid internal energy model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( physicsSolverBaseKernels::NormType const normType, - integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - constitutive::SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer, - real64 (& residualNorm)[3], - real64 (& residualNormalizer)[3] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, - numComps, numPhases, subRegion, fluid, solid, solidInternalEnergy, minNormalizer ); - if( normType == physicsSolverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - - } -}; - - -} // namespace thermalCompositionalMultiphaseBaseKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index 6926c0f10a8..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseFVMKernels.hpp +++ /dev/null @@ -1,1444 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ThermalCompositionalMultiphaseFVMKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP - -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp" - -#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp" -#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" -#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityFields.hpp" - -namespace geos -{ - -namespace thermalCompositionalMultiphaseFVMKernels -{ - -/******************************** PhaseMobilityKernel ********************************/ - -/** - * @class PhaseMobilityKernel - * @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 phase mobilities - */ -template< integer NUM_COMP, integer NUM_PHASE > -class PhaseMobilityKernel : public isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE > -{ -public: - - using Base = isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE >; - using Base::numPhase; - using Base::m_dPhaseVolFrac; - using Base::m_phaseDens; - using Base::m_dPhaseDens; - using Base::m_phaseVisc; - using Base::m_dPhaseVisc; - using Base::m_dPhaseRelPerm_dPhaseVolFrac; - - /** - * @brief Constructor - * @param[in] subRegion the element subregion - * @param[in] fluid the fluid model - * @param[in] relperm the relperm model - */ - PhaseMobilityKernel( ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::RelativePermeabilityBase const & relperm ) - : Base( subRegion, fluid, relperm ) - {} - - /** - * @brief Compute the phase mobilities in an element - * @param[in] ei the element index - */ - GEOS_HOST_DEVICE - inline - void compute( localIndex const ei ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; - arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; - - Base::compute( ei, [&] ( localIndex const ip, - real64 const & phaseMob, - arraySlice1d< real64, compflow::USD_PHASE_DC - 2 > const & dPhaseMob ) - { - // Step 1: compute the derivative of relPerm[ip] wrt temperature - real64 dRelPerm_dT = 0.0; - for( integer jp = 0; jp < numPhase; ++jp ) - { - dRelPerm_dT += dPhaseRelPerm_dPhaseVolFrac[ip][jp] * dPhaseVolFrac[jp][Deriv::dT]; - } - - // Step 2: compute the derivative of phaseMob[ip] wrt temperature - dPhaseMob[Deriv::dT] = dRelPerm_dT * phaseDens[ip] / phaseVisc[ip] - + phaseMob * (dPhaseDens[ip][Deriv::dT] / phaseDens[ip] - dPhaseVisc[ip][Deriv::dT] / phaseVisc[ip] ); - } ); - } - -}; - -/** - * @class PhaseMobilityKernelFactory - */ -class PhaseMobilityKernelFactory -{ -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 - * @param[in] relperm the relperm model - */ - template< typename POLICY > - static void - createAndLaunch( integer const numComp, - integer const numPhase, - ObjectManagerBase & subRegion, - constitutive::MultiFluidBase const & fluid, - constitutive::RelativePermeabilityBase const & relperm ) - { - if( numPhase == 2 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - else if( numPhase == 3 ) - { - isothermalCompositionalMultiphaseBaseKernels:: - internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) - { - integer constexpr NUM_COMP = NC(); - PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); - PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); - } ); - } - } -}; - - -/******************************** FaceBasedAssemblyKernel ********************************/ - -/** - * @class FaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_numPhases; - using AbstractBase::m_gravCoef; - using AbstractBase::m_phaseVolFrac; - using AbstractBase::m_dPhaseVolFrac; - using AbstractBase::m_phaseCompFrac; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dCompFrac_dCompDens; - - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::maxNumConns; - using Base::numFluxSupportPoints; - using Base::m_phaseMob; - using Base::m_dPhaseMob; - using Base::m_dPhaseMassDens; - using Base::m_dPhaseCapPressure_dPhaseVolFrac; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - - using ThermalCompFlowAccessors = - StencilAccessors< fields::flow::temperature >; - - using ThermalMultiFluidAccessors = - StencilMaterialAccessors< constitutive::MultiFluidBase, - fields::multifluid::phaseEnthalpy, - fields::multifluid::dPhaseEnthalpy >; - - using ThermalConductivityAccessors = - StencilMaterialAccessors< constitutive::MultiPhaseThermalConductivityBase, - fields::thermalconductivity::effectiveConductivity >; - // for now, we treat thermal conductivity explicitly - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dofNumberAccessor accessor for the dofs numbers - * @param[in] compFlowAccessor accessor for wrappers registered by the solver - * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver - * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model - * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model - * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model - * @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 all together - */ - FaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - ThermalCompFlowAccessors const & thermalCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), - m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), - m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), - m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : Base::StackVariables( size, numElems ) - {} - - using Base::StackVariables::stencilSize; - using Base::StackVariables::numConnectedElems; - using Base::StackVariables::transmissibility; - using Base::StackVariables::dTrans_dPres; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - // Thermal transmissibility (for now, no derivatives) - - real64 thermalTransmissibility[maxNumConns][2]{}; - }; - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute: - // 1) compFlux and its derivatives (including derivatives wrt temperature), - // 2) enthalpy part of convectiveEnergyFlux and its derivatives (including derivatives wrt temperature) - // - // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, - // such as potGrad, phaseFlux, and the indices of the upwind cell - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeFlux( iconn, stack, [&] ( integer const ip, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const potGrad, - real64 const phaseFlux, - real64 const (&dPhaseFlux_dP)[2], - real64 const (&dPhaseFlux_dC)[2][numComp] ) - { - // We are in the loop over phases, ip provides the current phase index. - - // Step 1: compute the derivatives of the mean density at the interface wrt temperature - - real64 dDensMean_dT[numFluxSupportPoints]{}; - - real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], - stack.transmissibility[connectionIndex][1] }; - - real64 convectiveEnergyFlux = 0.0; - real64 dConvectiveEnergyFlux_dP[numFluxSupportPoints]{}; - real64 dConvectiveEnergyFlux_dT[numFluxSupportPoints]{}; - real64 dConvectiveEnergyFlux_dC[numFluxSupportPoints][numComp]{}; - real64 dCompFlux_dT[numFluxSupportPoints][numComp]{}; - - integer denom = 0; - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - bool const phaseExists = (m_phaseVolFrac[er_up][esr_up][ei_up][ip] > 0); - if( !phaseExists ) - { - continue; - } - - dDensMean_dT[i] = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; - denom++; - } - if( denom > 1 ) - { - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - dDensMean_dT[i] /= denom; - } - } - - // Step 2: compute the derivatives of the phase potential difference wrt temperature - //***** calculation of flux ***** - - real64 dPresGrad_dT[numFluxSupportPoints]{}; - real64 dGravHead_dT[numFluxSupportPoints]{}; - - // compute potential difference MPFA-style - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - // Step 2.1: compute derivative of capillary pressure wrt temperature - real64 dCapPressure_dT = 0.0; - if( AbstractBase::m_kernelFlags.isSet( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ) ) - { - for( integer jp = 0; jp < m_numPhases; ++jp ) - { - real64 const dCapPressure_dS = m_dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; - dCapPressure_dT += dCapPressure_dS * m_dPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; - } - } - - // Step 2.2: compute derivative of phase pressure difference wrt temperature - dPresGrad_dT[i] -= trans[i] * dCapPressure_dT; - real64 const gravD = trans[i] * m_gravCoef[er][esr][ei]; - - // Step 2.3: compute derivative of gravity potential difference wrt temperature - for( integer j = 0; j < numFluxSupportPoints; ++j ) - { - dGravHead_dT[j] += dDensMean_dT[j] * gravD; - } - } - - // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature - // *** upwinding *** - - // note: the upwinding is done in the base class, which is in charge of - // computing the following quantities: potGrad, phaseFlux, k_up, er_up, esr_up, ei_up - - real64 dPhaseFlux_dT[numFluxSupportPoints]{}; - - // Step 3.1: compute the derivative of phase flux wrt temperature - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dT[ke] += dPresGrad_dT[ke]; - } - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dT[ke] -= dGravHead_dT[ke]; - } - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dT[ke] *= m_phaseMob[er_up][esr_up][ei_up][ip]; - } - dPhaseFlux_dT[k_up] += m_dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dT] * potGrad; - - // Step 3.2: compute the derivative of component flux wrt temperature - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = - m_phaseCompFrac[er_up][esr_up][ei_up][0][ip]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = - m_dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; - - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dCompFlux_dT[ke][ic] += dPhaseFlux_dT[ke] * ycp; - } - dCompFlux_dT[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; - } - - // Step 4: add dCompFlux_dTemp to localFluxJacobian - for( integer ic = 0; ic < numComp; ++ic ) - { - integer const eqIndex0 = k[0]* numEqn + ic; - integer const eqIndex1 = k[1]* numEqn + ic; - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; - stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dCompFlux_dT[ke][ic]; - stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dCompFlux_dT[ke][ic]; - } - } - - // Step 5: compute the enthalpy flux - real64 const enthalpy = m_phaseEnthalpy[er_up][esr_up][ei_up][0][ip]; - convectiveEnergyFlux += phaseFlux * enthalpy; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dConvectiveEnergyFlux_dP[ke] += dPhaseFlux_dP[ke] * enthalpy; - dConvectiveEnergyFlux_dT[ke] += dPhaseFlux_dT[ke] * enthalpy; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dConvectiveEnergyFlux_dC[ke][jc] += dPhaseFlux_dC[ke][jc] * enthalpy; - } - } - - dConvectiveEnergyFlux_dP[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dP]; - dConvectiveEnergyFlux_dT[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dT]; - - real64 dProp_dC[numComp]{}; - applyChainRule( numComp, - m_dCompFrac_dCompDens[er_up][esr_up][ei_up], - m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dConvectiveEnergyFlux_dC[k_up][jc] += phaseFlux * dProp_dC[jc]; - } - - // Step 6: add convectiveFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; - integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; - stack.localFlux[localRowIndexEnergy0] += m_dt * convectiveEnergyFlux; - stack.localFlux[localRowIndexEnergy1] -= m_dt * convectiveEnergyFlux; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - integer const localDofIndexPres = k[ke] * numDof; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexPres] += m_dt * dConvectiveEnergyFlux_dP[ke]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexPres] -= m_dt * dConvectiveEnergyFlux_dP[ke]; - integer const localDofIndexTemp = localDofIndexPres + numDof - 1; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConvectiveEnergyFlux_dT[ke]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConvectiveEnergyFlux_dT[ke]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - integer const localDofIndexComp = localDofIndexPres + jc + 1; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexComp] += m_dt * dConvectiveEnergyFlux_dC[ke][jc]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexComp] -= m_dt * dConvectiveEnergyFlux_dC[ke][jc]; - } - } - } ); - - // ***************************************************** - // Computation of the conduction term in the energy flux - // Note that the phase enthalpy term in the energy was computed above - // Note that this term is computed using an explicit treatment of conductivity for now - - // Step 1: compute the thermal transmissibilities at this face - // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity - // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice - // TODO: modify computeWeights to accomodate explicit coefficients - m_stencilWrapper.computeWeights( iconn, - m_thermalConductivity, - m_thermalConductivity, // we have to pass something here, so we just use thermal conductivity - stack.thermalTransmissibility, - stack.dTrans_dPres ); // again, we have to pass something here, but this is unused for now - - - - localIndex k[2]{}; - localIndex connectionIndex = 0; - - for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) - { - for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) - { - real64 const thermalTrans[2] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] }; - localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; - localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; - localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; - - real64 conductiveEnergyFlux = 0.0; - real64 dConductiveEnergyFlux_dT[numFluxSupportPoints]{}; - - // Step 2: compute temperature difference at the interface - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const er = seri[ke]; - localIndex const esr = sesri[ke]; - localIndex const ei = sei[ke]; - - conductiveEnergyFlux += thermalTrans[ke] * m_temp[er][esr][ei]; - dConductiveEnergyFlux_dT[ke] += thermalTrans[ke]; - } - - // Step 3: add conductiveFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; - integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; - stack.localFlux[localRowIndexEnergy0] += m_dt * conductiveEnergyFlux; - stack.localFlux[localRowIndexEnergy1] -= m_dt * conductiveEnergyFlux; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; - stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConductiveEnergyFlux_dT[ke]; - stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConductiveEnergyFlux_dT[ke]; - } - } - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void complete( localIndex const iconn, - StackVariables & stack ) const - { - // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) - // In the lambda, add contribution to residual and jacobian into the energy balance equation - Base::complete( iconn, stack, [&] ( integer const i, - localIndex const localRow ) - { - // beware, there is volume balance eqn in m_localRhs and m_localMatrix! - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[i * numEqn + numEqn-1] ); - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + numEqn, - stack.dofColIndices.data(), - stack.localFluxJacobian[i * numEqn + numEqn-1].dataIfContiguous(), - stack.stencilSize * numDof ); - - } ); - } - -protected: - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on phase enthalpies - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseEnthalpy; - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; - - /// View on thermal conductivity - ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; - // for now, we treat thermal conductivity explicitly - -}; - -/** - * @class FaceBasedAssemblyKernelFactory - */ -class FaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @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 string to get the element degrees of freedom numbers - * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not - * @param[in] solverName name of the solver (to name accessors) - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasCapPressure, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - 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; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( hasCapPressure ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ); - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using KernelType = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); - typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); - typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); - - KernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, - compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, - capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - -/******************************** DiffusionDispersionFaceBasedAssemblyKernel ********************************/ - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class DiffusionDispersionFaceBasedAssemblyKernel : - public isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using AbstractBase::m_dt; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dPhaseVolFrac; - - using Base = typename isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - using DiffusionAccessors = typename Base::DiffusionAccessors; - using DispersionAccessors = typename Base::DispersionAccessors; - using PorosityAccessors = typename Base::PorosityAccessors; - using Base::numFluxSupportPoints; - using Base::numEqn; - using Base::numComp; - using Base::numDof; - using Base::m_referencePorosity; - using Base::m_phaseVolFrac; - using Base::m_phaseDens; - using Base::m_dPhaseDens; - using Base::m_phaseDiffusivityMultiplier; - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @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] diffusionAccessors - * @param[in] dispersionAccessors - * @param[in] porosityAccessors - * @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 - */ - DiffusionDispersionFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - DiffusionAccessors const & diffusionAccessors, - DispersionAccessors const & dispersionAccessors, - PorosityAccessors const & porosityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - stencilWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - diffusionAccessors, - dispersionAccessors, - porosityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ) - {} - - struct StackVariables : public Base::StackVariables - { -public: - - GEOS_HOST_DEVICE - StackVariables( localIndex const size, localIndex numElems ) - : Base::StackVariables( size, numElems ) - {} - - using Base::StackVariables::transmissibility; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - }; - - /** - * @brief Compute the local diffusion flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void computeDiffusionFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute the diffusionFlux and its derivatives (including derivatives wrt temperature), - // - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeDiffusionFlux( iconn, stack, [&] ( integer const ip, - integer const ic, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const compFracGrad, - real64 const upwindCoefficient ) - { - // We are in the loop over phases and components, ip provides the current phase index. - - real64 dCompFracGrad_dT[numFluxSupportPoints]{}; - real64 dDiffusionFlux_dT[numFluxSupportPoints]{}; - - /// compute the TPFA component difference - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; - } - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dDiffusionFlux_dT[ke] += upwindCoefficient * dCompFracGrad_dT[ke]; - } - - // add contributions of the derivatives of upwind coefficient wrt temperature - real64 const dUpwindCoefficient_dT = - m_referencePorosity[er_up][esr_up][ei_up] * - m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * - ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] - + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dT] ); - dDiffusionFlux_dT[k_up] += dUpwindCoefficient_dT * compFracGrad; - - // finally, increment local flux and local Jacobian - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDiffusionFlux_dT[ke]; - stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDiffusionFlux_dT[ke]; - } - } ); - } - - /** - * @brief Compute the local dispersion flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - inline - void computeDispersionFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Deriv = constitutive::multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute the dispersionFlux and its derivatives (including derivatives wrt temperature), - // - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeDispersionFlux( iconn, stack, [&] ( integer const ip, - integer const ic, - localIndex const (&k)[2], - localIndex const (&seri)[2], - localIndex const (&sesri)[2], - localIndex const (&sei)[2], - localIndex const connectionIndex, - localIndex const k_up, - localIndex const er_up, - localIndex const esr_up, - localIndex const ei_up, - real64 const compFracGrad ) - { - // We are in the loop over phases and components, ip provides the current phase index. - - real64 dCompFracGrad_dT[numFluxSupportPoints]{}; - real64 dDispersionFlux_dT[numFluxSupportPoints]{}; - - /// compute the TPFA component difference - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; - } - - // add contributions of the derivatives of component fractions wrt pressure/component fractions - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dDispersionFlux_dT[ke] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dT[ke]; - } - - // add contributions of the derivatives of upwind coefficient wrt temperature - dDispersionFlux_dT[k_up] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * compFracGrad; - - // finally, increment local flux and local Jacobian - integer const eqIndex0 = k[0] * numEqn + ic; - integer const eqIndex1 = k[1] * numEqn + ic; - - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; - stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDispersionFlux_dT[ke]; - stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDispersionFlux_dT[ke]; - } - } ); - } -}; - -/** - * @class DiffusionDispersionFaceBasedAssemblyKernelFactory - */ -class DiffusionDispersionFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @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 string to get the element degrees of freedom numbers - * @param[in] hasDiffusion flag specifying whether diffusion is used or not - * @param[in] hasDispersion flag specifying whether dispersion is used or not - * @param[in] solverName the name of the solver - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - string const & dofKey, - integer const hasDiffusion, - integer const hasDispersion, - integer const useTotalMassEquation, - string const & solverName, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - real64 const dt, - 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; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using kernelType = DiffusionDispersionFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; - typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); - typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); - typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); - - kernelType kernel( numPhases, rankOffset, stencilWrapper, - dofNumberAccessor, compFlowAccessors, multiFluidAccessors, - diffusionAccessors, dispersionAccessors, porosityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - kernelType::template launch< POLICY >( stencilWrapper.size(), - hasDiffusion, hasDispersion, - kernel ); - } ); - } -}; - -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichletFaceBasedAssemblyKernel - * @tparam NUM_COMP number of fluid components - * @tparam NUM_DOF number of degrees of freedom - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_COMP, - NUM_DOF, - FLUIDWRAPPER > -{ -public: - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using CompFlowAccessors = AbstractBase::CompFlowAccessors; - using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; - using CapPressureAccessors = AbstractBase::CapPressureAccessors; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_gravCoef; - using AbstractBase::m_phaseCompFrac; - using AbstractBase::m_dPhaseCompFrac; - using AbstractBase::m_dCompFrac_dCompDens; - - using Base = isothermalCompositionalMultiphaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, FLUIDWRAPPER >; - using Base::numComp; - using Base::numDof; - using Base::numEqn; - using Base::m_phaseMob; - using Base::m_dPhaseMob; - using Base::m_dPhaseMassDens; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - using Base::m_faceTemp; - using Base::m_faceGravCoef; - - - using ThermalCompFlowAccessors = - StencilAccessors< fields::flow::temperature >; - - using ThermalMultiFluidAccessors = - StencilMaterialAccessors< constitutive::MultiFluidBase, - fields::multifluid::phaseEnthalpy, - fields::multifluid::dPhaseEnthalpy >; - - using ThermalConductivityAccessors = - StencilMaterialAccessors< constitutive::MultiPhaseThermalConductivityBase, - fields::thermalconductivity::effectiveConductivity >; - // for now, we treat thermal conductivity explicitly - - /** - * @brief Constructor for the kernel interface - * @param[in] numPhases the number of fluid phases - * @param[in] rankOffset the offset of my MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid wrapper - * @param[in] dofNumberAccessor accessor for the dofs numbers - * @param[in] compFlowAccessor accessor for wrappers registered by the solver - * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver - * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model - * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model - * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model - * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model - * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model - * @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 - */ - DirichletFaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - ThermalCompFlowAccessors const & thermalCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) - : Base( numPhases, - rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - compFlowAccessors, - multiFluidAccessors, - capPressureAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs, - kernelFlags ), - m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), - m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), - m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), - m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) - {} - - struct StackVariables : public Base::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, localIndex numElems ) - : Base::StackVariables( size, numElems ) - {} - - using Base::StackVariables::transmissibility; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - - // Component fluxes and derivatives - - /// Derivatives of component fluxes wrt temperature - real64 dCompFlux_dT[numComp]{}; - - - // Energy fluxes and derivatives - - /// Energy fluxes - real64 energyFlux = 0.0; - /// Derivative of energy fluxes wrt pressure - real64 dEnergyFlux_dP = 0.0; - /// Derivative of energy fluxes wrt temperature - real64 dEnergyFlux_dT = 0.0; - /// Derivatives of energy fluxes wrt component densities - real64 dEnergyFlux_dC[numComp]{}; - - }; - - /** - * @brief Compute the local flux contributions to the residual and Jacobian - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - using Order = BoundaryStencil::Order; - using Deriv = constitutive::multifluid::DerivativeOffset; - - // *********************************************** - // First, we call the base computeFlux to compute: - // 1) compFlux and its derivatives (including derivatives wrt temperature), - // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature) - // - // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, - // such as potGrad, phaseFlux, and the indices of the upwind cell - // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables - Base::computeFlux( iconn, stack, [&] ( integer const ip, - localIndex const er, - localIndex const esr, - localIndex const ei, - localIndex const kf, - real64 const f, // potGrad times trans - real64 const facePhaseMob, - arraySlice1d< const real64, constitutive::multifluid::USD_PHASE - 2 > const & facePhaseEnthalpy, - arraySlice2d< const real64, constitutive::multifluid::USD_PHASE_COMP-2 > const & facePhaseCompFrac, - real64 const phaseFlux, - real64 const dPhaseFlux_dP, - real64 const (&dPhaseFlux_dC)[numComp] ) - { - // We are in the loop over phases, ip provides the current phase index. - - // Step 1: compute the derivatives of the mean density at the interface wrt temperature - - real64 const dDensMean_dT = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; - - // Step 2: compute the derivatives of the phase potential difference wrt temperature - //***** calculation of flux ***** - - real64 const dF_dT = -stack.transmissibility * dDensMean_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); - - // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature - // *** upwinding *** - - // note: the upwinding is done in the base class, which is in charge of - // computing the following quantities: potGrad, phaseFlux - // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way - - - if( f >= 0 ) // the element is upstream - { - - // Step 3.1.a: compute the derivative of phase flux wrt temperature - real64 const dPhaseFlux_dT = m_phaseMob[er][esr][ei][ip] * dF_dT + m_dPhaseMob[er][esr][ei][ip][Deriv::dT] * f; - - // Step 3.2.a: compute the derivative of component flux wrt temperature - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = - m_phaseCompFrac[er][esr][ei][0][ip]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = - m_dPhaseCompFrac[er][esr][ei][0][ip]; - - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; - } - - // Step 3.3.a: compute the enthalpy flux - - real64 const enthalpy = m_phaseEnthalpy[er][esr][ei][0][ip]; - stack.energyFlux += phaseFlux * enthalpy; - stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; - stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; - - real64 dProp_dC[numComp]{}; - applyChainRule( numComp, - m_dCompFrac_dCompDens[er][esr][ei], - m_dPhaseEnthalpy[er][esr][ei][0][ip], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy + phaseFlux * dProp_dC[jc]; - } - - } - else // the face is upstream - { - - // Step 3.1.b: compute the derivative of phase flux wrt temperature - real64 const dPhaseFlux_dT = facePhaseMob * dF_dT; - - // Step 3.2.b: compute the derivative of component flux wrt temperature - - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = facePhaseCompFrac[ip][ic]; - stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp; - } - - // Step 3.3.b: compute the enthalpy flux - - real64 const enthalpy = facePhaseEnthalpy[ip]; - stack.energyFlux += phaseFlux * enthalpy; - stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy; - stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy; - } - - } - - } ); - - // ***************************************************** - // Computation of the conduction term in the energy flux - // Note that the phase enthalpy term in the energy was computed above - // Note that this term is computed using an explicit treatment of conductivity for now - - // Step 1: compute the thermal transmissibilities at this face - // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity - // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice - // TODO: modify computeWeights to accomodate explicit coefficients - real64 thermalTrans = 0.0; - real64 dThermalTrans_dPerm[3]{}; // not used - m_stencilWrapper.computeWeights( iconn, - m_thermalConductivity, - thermalTrans, - dThermalTrans_dPerm ); - - // Step 2: compute temperature difference at the interface - stack.energyFlux += thermalTrans - * ( m_temp[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] - m_faceTemp[m_sei( iconn, Order::FACE )] ); - stack.dEnergyFlux_dT += thermalTrans; - - - // ********************************************************************************** - // At this point, we have computed the energyFlux and the compFlux for all components - // We have to do two things here: - // 1) Add dCompFlux_dTemp to the localFluxJacobian of the component mass balance equations - // 2) Add energyFlux and its derivatives to the localFlux(Jacobian) of the energy balance equation - - // Step 1: add dCompFlux_dTemp to localFluxJacobian - for( integer ic = 0; ic < numComp; ++ic ) - { - stack.localFluxJacobian[ic][numDof-1] = m_dt * stack.dCompFlux_dT[ic]; - } - - // Step 2: add energyFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy = numEqn-1; - stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; - - stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; - stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; - for( integer jc = 0; jc < numComp; ++jc ) - { - stack.localFluxJacobian[localRowIndexEnergy][jc+1] = m_dt * stack.dEnergyFlux_dC[jc]; - } - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack ) const - { - // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) - // In the lambda, add contribution to residual and jacobian into the energy balance equation - Base::complete( iconn, stack, [&] ( localIndex const localRow ) - { - // beware, there is volume balance eqn in m_localRhs and m_localMatrix! - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[numEqn-1] ); - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + numEqn, - stack.dofColIndices, - stack.localFluxJacobian[numEqn-1], - numDof ); - - } ); - } - -protected: - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on phase enthalpies - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseEnthalpy; - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; - - /// View on thermal conductivity - ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; - // for now, we treat thermal conductivity explicitly - -}; - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @tparam STENCILWRAPPER the type of the stencil wrapper - * @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 string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidBase the multifluid constitutive model - * @param[in] dt time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - template< typename POLICY, typename STENCILWRAPPER > - static void - createAndLaunch( integer const numComps, - integer const numPhases, - globalIndex const rankOffset, - integer const useTotalMassEquation, - string const & dofKey, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - STENCILWRAPPER const & stencilWrapper, - constitutive::MultiFluidBase & fluidBase, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutive::constitutiveComponentUpdatePassThru< true >( fluidBase, numComps, [&]( auto & fluid, auto NC ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); - - integer constexpr NUM_COMP = NC(); - integer constexpr NUM_DOF = NC() + 2; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - // for now, we neglect capillary pressure in the kernel - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; - if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); - - using KernelType = DirichletFaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; - typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); - typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); - typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); - typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); - typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); - typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); - - KernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, - dofNumberAccessor, compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, - capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, - dt, localMatrix, localRhs, kernelFlags ); - KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } -}; - - -} // namespace thermalCompositionalMultiphaseFVMKernels - -} // namespace geos - - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseBaseKernels.hpp deleted file mode 100644 index d17b79e308c..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseBaseKernels.hpp +++ /dev/null @@ -1,626 +0,0 @@ -/* - * ------------------------------------------------------------------------------------------------------------ - * SPDX-License-Identifier: LGPL-2.1-only - * - * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC - * Copyright (c) 2018-2024 Total, S.A - * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University - * Copyright (c) 2023-2024 Chevron - * Copyright (c) 2019- GEOS/GEOSX Contributors - * All rights reserved - * - * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. - * ------------------------------------------------------------------------------------------------------------ - */ - -/** - * @file ThermalSinglePhaseBaseKernels.hpp - */ - -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEBASEKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEBASEKERNELS_HPP - -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" - -namespace geos -{ - -namespace thermalSinglePhaseBaseKernels -{ - -/******************************** MobilityKernel ********************************/ - -struct MobilityKernel -{ - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & dDens_dPres, - real64 const & dDens_dTemp, - real64 const & visc, - real64 const & dVisc_dPres, - real64 const & dVisc_dTemp, - real64 & mob, - real64 & dMob_dPres, - real64 & dMob_dTemp ) - { - mob = dens / visc; - dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; - dMob_dTemp = dDens_dTemp / visc - mob / visc * dVisc_dTemp; - } - - GEOS_HOST_DEVICE - inline - static void - compute( real64 const & dens, - real64 const & visc, - real64 & mob ) - { - mob = dens / visc; - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & dDens_dPres, - arrayView2d< real64 const > const & dDens_dTemp, - arrayView2d< real64 const > const & visc, - arrayView2d< real64 const > const & dVisc_dPres, - arrayView2d< real64 const > const & dVisc_dTemp, - arrayView1d< real64 > const & mob, - arrayView1d< real64 > const & dMob_dPres, - arrayView1d< real64 > const & dMob_dTemp ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - dDens_dPres[a][0], - dDens_dTemp[a][0], - visc[a][0], - dVisc_dPres[a][0], - dVisc_dTemp[a][0], - mob[a], - dMob_dPres[a], - dMob_dTemp[a] ); - } ); - } - - template< typename POLICY > - static void launch( localIndex const size, - arrayView2d< real64 const > const & dens, - arrayView2d< real64 const > const & visc, - arrayView1d< real64 > const & mob ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) - { - compute( dens[a][0], - visc[a][0], - mob[a] ); - } ); - } -}; - -/******************************** ElementBasedAssemblyKernel ********************************/ - -/** - * @class ElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation - */ -template< typename SUBREGION_TYPE, integer NUM_DOF > -class ElementBasedAssemblyKernel : public singlePhaseBaseKernels::ElementBasedAssemblyKernel< SUBREGION_TYPE, NUM_DOF > -{ - -public: - - using Base = singlePhaseBaseKernels::ElementBasedAssemblyKernel< SUBREGION_TYPE, NUM_DOF >; - using Base::numDof; - using Base::numEqn; - using Base::m_rankOffset; - using Base::m_dofNumber; - using Base::m_elemGhostRank; - using Base::m_volume; - using Base::m_deltaVolume; - using Base::m_porosity; - using Base::m_dPoro_dPres; - using Base::m_density; - using Base::m_dDensity_dPres; - using Base::m_localMatrix; - using Base::m_localRhs; - - /** - * @brief Constructor - * @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( globalIndex const rankOffset, - string const dofKey, - SUBREGION_TYPE const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ), - m_dDensity_dTemp( fluid.dDensity_dTemperature() ), - m_dPoro_dTemp( solid.getDporosity_dTemperature() ), - m_internalEnergy( fluid.internalEnergy() ), - m_dInternalEnergy_dPres( fluid.dInternalEnergy_dPressure() ), - m_dInternalEnergy_dTemp( fluid.dInternalEnergy_dTemperature() ), - m_rockInternalEnergy( solid.getInternalEnergy() ), - m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ), - m_energy_n( subRegion.template getField< fields::flow::energy_n >() ) - {} - - /** - * @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::poreVolume; - using Base::StackVariables::dPoreVolume_dPres; - using Base::StackVariables::localRow; - using Base::StackVariables::dofIndices; - using Base::StackVariables::localResidual; - using Base::StackVariables::localJacobian; - - /// Derivative of pore volume with respect to temperature - real64 dPoreVolume_dTemp = 0.0; - - // Solid energy - - /// Solid energy at time n+1 - real64 solidEnergy = 0.0; - - /// Derivative of solid internal energy with respect to pressure - real64 dSolidEnergy_dPres = 0.0; - - /// Derivative of solid internal energy with respect to temperature - real64 dSolidEnergy_dTemp = 0.0; - }; - - - /** - * @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 ); - - stack.dPoreVolume_dTemp = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; - - // initialize the solid volume - real64 const solidVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * ( 1.0 - m_porosity[ei][0] ); - real64 const dSolidVolume_dPres = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; - real64 const dSolidVolume_dTemp = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; - - // initialize the solid internal energy - stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; - stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; - stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] + dSolidVolume_dTemp * m_rockInternalEnergy[ei][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] kernelOp the function used to customize the kernel - */ - GEOS_HOST_DEVICE - void computeAccumulation( localIndex const ei, - StackVariables & stack ) const - { - stack.localResidual[numEqn-1] = -m_energy_n[ei]; - - Base::computeAccumulation( ei, stack, [&] () - { - // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature - stack.localJacobian[0][numDof-1] = stack.poreVolume * m_dDensity_dTemp[ei][0] + stack.dPoreVolume_dTemp * m_density[ei][0]; - - // Step 2: assemble the fluid part of the accumulation term of the energy equation - real64 const fluidEnergy = stack.poreVolume * m_density[ei][0] * m_internalEnergy[ei][0]; - - real64 const dFluidEnergy_dP = stack.dPoreVolume_dPres * m_density[ei][0] * m_internalEnergy[ei][0] - + stack.poreVolume * m_dDensity_dPres[ei][0] * m_internalEnergy[ei][0] - + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dPres[ei][0]; - - real64 const dFluidEnergy_dT = stack.poreVolume * m_dDensity_dTemp[ei][0] * m_internalEnergy[ei][0] - + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dTemp[ei][0] - + stack.dPoreVolume_dTemp * m_density[ei][0] * m_internalEnergy[ei][0]; - - // local accumulation - stack.localResidual[numEqn-1] += fluidEnergy; - - // derivatives w.r.t. pressure and temperature - stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; - stack.localJacobian[numEqn-1][numDof-1] = dFluidEnergy_dT; - } ); - - // Step 3: assemble the solid part of the accumulation term of the energy equation - stack.localResidual[numEqn-1] += stack.solidEnergy; - stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; - stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; - } - - /** - * @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 ei, - StackVariables & stack ) const - { - // Step 1: assemble the mass balance equation - Base::complete( ei, stack ); - - // Step 2: assemble the energy equation - m_localRhs[stack.localRow + numEqn-1] += stack.localResidual[numEqn-1]; - m_localMatrix.template addToRow< serialAtomic >( stack.localRow + numEqn-1, - stack.dofIndices, - stack.localJacobian[numEqn-1], - numDof ); - - - } - -protected: - - /// View on derivative of fluid density w.r.t temperature - arrayView2d< real64 const > const m_dDensity_dTemp; - - /// View on derivative of porosity w.r.t temperature - arrayView2d< real64 const > const m_dPoro_dTemp; - - /// Views on fluid internal energy - arrayView2d< real64 const > const m_internalEnergy; - arrayView2d< real64 const > const m_dInternalEnergy_dPres; - arrayView2d< real64 const > const m_dInternalEnergy_dTemp; - - /// Views on rock internal energy - arrayView2d< real64 const > const m_rockInternalEnergy; - arrayView2d< real64 const > const m_dRockInternalEnergy_dTemp; - - /// View on energy - arrayView1d< real64 const > const m_energy_n; - -}; - -/** - * @class SurfaceElementBasedAssemblyKernel - * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion - */ -class SurfaceElementBasedAssemblyKernel : public ElementBasedAssemblyKernel< SurfaceElementSubRegion, 2 > -{ - -public: - - using Base = ElementBasedAssemblyKernel< SurfaceElementSubRegion, 2 >; - - /** - * @brief Constructor - * @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 - */ - SurfaceElementBasedAssemblyKernel( globalIndex const rankOffset, - string const dofKey, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ), - m_creationMass( subRegion.getField< fields::flow::massCreated >() ) - {} - - /** - * @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, - Base::StackVariables & stack ) const - { - Base::computeAccumulation( ei, stack ); - if( Base::m_mass_n[ei] > 1.1 * m_creationMass[ei] ) - { - stack.localResidual[0] += m_creationMass[ei] * 0.25; - } - } - -protected: - - arrayView1d< real64 const > const m_creationMass; - -}; - -/** - * @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[in] solid the solid 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, - CellElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - integer constexpr NUM_DOF = 2; - - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF > - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF >::template - launch< POLICY, ElementBasedAssemblyKernel< CellElementSubRegion, NUM_DOF > >( subRegion.size(), kernel ); - } - - /** - * @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[in] solid the solid 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, - SurfaceElementSubRegion const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - SurfaceElementBasedAssemblyKernel - kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); - SurfaceElementBasedAssemblyKernel::launch< POLICY >( subRegion.size(), kernel ); - } - - -}; - - -/******************************** FluidUpdateKernel ********************************/ - -struct FluidUpdateKernel -{ - template< typename FLUID_WRAPPER > - static void launch( FLUID_WRAPPER const & fluidWrapper, - arrayView1d< real64 const > const & pres, - arrayView1d< real64 const > const & temp ) - { - forAll< parallelDevicePolicy<> >( fluidWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) - { - fluidWrapper.update( k, q, pres[k], temp[k] ); - } - } ); - } -}; - -/******************************** SolidInternalEnergyUpdateKernel ********************************/ - -struct SolidInternalEnergyUpdateKernel -{ - - template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > - static void - launch( localIndex const size, - SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, - arrayView1d< real64 const > const & temp ) - { - forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) - { - solidInternalEnergyWrapper.update( k, temp[k] ); - } ); - } -}; - -/******************************** ResidualNormKernel ********************************/ - -/** - * @class ResidualNormKernel - */ -class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 > -{ -public: - - using Base = physicsSolverBaseKernels::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, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - constitutive::SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer ) - : Base( rankOffset, - localResidual, - dofNumber, - ghostRank, - minNormalizer ), - m_volume( subRegion.getElementVolume() ), - m_porosity_n( solid.getPorosity_n() ), - m_density_n( fluid.density_n() ), - m_fluidInternalEnergy_n( fluid.internalEnergy_n() ), - m_solidInternalEnergy_n( solidInternalEnergy.getInternalEnergy_n() ) - {} - - GEOS_HOST_DEVICE - void computeMassEnergyNormalizers( localIndex const ei, - real64 & massNormalizer, - real64 & energyNormalizer ) const - { - massNormalizer = LvArray::math::max( m_minNormalizer, m_density_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); - energyNormalizer = - LvArray::math::max( m_minNormalizer, - LvArray::math::abs( m_solidInternalEnergy_n[ei][0] * ( 1.0 - m_porosity_n[ei][0] ) * m_volume[ei] - + m_fluidInternalEnergy_n[ei][0] * m_density_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ) ); - } - - GEOS_HOST_DEVICE - virtual void computeLinf( localIndex const ei, - LinfStackVariables & stack ) const override - { - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - - // step 1: mass residual - - real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; - if( valMass > stack.localValue[0] ) - { - stack.localValue[0] = valMass; - } - - // step 2: energy residual - real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + 1] ) / energyNormalizer; - if( valEnergy > stack.localValue[1] ) - { - stack.localValue[1] = valEnergy; - } - } - - GEOS_HOST_DEVICE - virtual void computeL2( localIndex const ei, - L2StackVariables & stack ) const override - { - real64 massNormalizer = 0.0, energyNormalizer = 0.0; - computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); - - // step 1: mass residual - - stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; - stack.localNormalizer[0] += massNormalizer; - - // step 2: energy residual - - stack.localValue[1] += m_localResidual[stack.localRow + 1] * m_localResidual[stack.localRow + 1]; - stack.localNormalizer[1] += energyNormalizer; - } - - -protected: - - /// View on the volume - arrayView1d< real64 const > const m_volume; - - /// View on porosity at the previous converged time step - arrayView2d< real64 const > const m_porosity_n; - - /// View on total mass/molar density at the previous converged time step - arrayView2d< real64 const > const m_density_n; - arrayView2d< real64 const > const m_fluidInternalEnergy_n; - - /// View on solid internal energy at the previous converged time step - arrayView2d< real64 const > const m_solidInternalEnergy_n; - -}; - -/** - * @class ResidualNormKernelFactory - */ -class ResidualNormKernelFactory -{ -public: - - /** - * @brief Create a new kernel and launch - * @tparam POLICY the policy used in the RAJA kernel - * @param[in] normType the type of norm used (Linf or L2) - * @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 element subregion - * @param[in] fluid the fluid model - * @param[in] solid the solid model - * @param[in] solidInternalEnergy the solid internal energy model - * @param[out] residualNorm the residual norm on the subRegion - * @param[out] residualNormalizer the residual normalizer on the subRegion - */ - template< typename POLICY > - static void - createAndLaunch( physicsSolverBaseKernels::NormType const normType, - globalIndex const rankOffset, - string const & dofKey, - arrayView1d< real64 const > const & localResidual, - ElementSubRegionBase const & subRegion, - constitutive::SingleFluidBase const & fluid, - constitutive::CoupledSolidBase const & solid, - constitutive::SolidInternalEnergy const & solidInternalEnergy, - real64 const minNormalizer, - real64 (& residualNorm)[2], - real64 (& residualNormalizer)[2] ) - { - arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); - arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); - - ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, fluid, solid, solidInternalEnergy, minNormalizer ); - if( normType == physicsSolverBaseKernels::NormType::Linf ) - { - ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); - } - else // L2 norm - { - ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); - } - } - -}; - -} // namespace thermalSinglePhaseBaseKernels - -} // namespace geos - -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp new file mode 100644 index 00000000000..f749853ad6f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp @@ -0,0 +1,510 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AccumulationKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/solid/CoupledSolidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "mesh/ElementSubRegionBase.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +static constexpr real64 minDensForDivision = 1e-10; + +enum class KernelFlags +{ + SimpleAccumulation = 1 << 0, // 1 + TotalMassEquation = 1 << 1, // 2 + /// Add more flags like that if needed: + // Flag3 = 1 << 2, // 4 + // Flag4 = 1 << 3, // 8 + // Flag5 = 1 << 4, // 16 + // Flag6 = 1 << 5, // 32 + // Flag7 = 1 << 6, // 64 + // Flag8 = 1 << 7 //128 +}; + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @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 AccumulationKernel +{ +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 + */ + AccumulationKernel( localIndex const numPhases, + globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > const kernelFlags ) + : m_numPhases( numPhases ), + m_rankOffset( rankOffset ), + m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), + m_elemGhostRank( subRegion.ghostRank() ), + m_volume( subRegion.getElementVolume() ), + m_porosity( solid.getPorosity() ), + m_dPoro_dPres( solid.getDporosity_dPressure() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ), + m_phaseCompFrac( fluid.phaseCompFraction() ), + m_dPhaseCompFrac( fluid.dPhaseCompFraction() ), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_compAmount_n( subRegion.getField< fields::flow::compAmount_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: + + // Pore volume information (used by both accumulation and volume balance) + + /// Pore volume at time n+1 + real64 poreVolume = 0.0; + + /// Derivative of pore volume with respect to pressure + real64 dPoreVolume_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]{}; + + /// 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 pore volume + stack.poreVolume = m_volume[ei] * m_porosity[ei][0]; + stack.dPoreVolume_dPres = m_volume[ei] * m_dPoro_dPres[ei][0]; + + // 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 + { + if( m_kernelFlags.isSet( KernelFlags::SimpleAccumulation ) ) + { + // 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 compAmount = stack.poreVolume * m_compDens[ei][ic]; + real64 const compAmount_n = m_compAmount_n[ei][ic]; + + stack.localResidual[ic] += compAmount - compAmount_n; + + // Pavel: commented below is some experiment, needs to be re-tested + //real64 const compDens = (ic == 0 && m_compDens[ei][ic] < 1e-6) ? 1e-3 : m_compDens[ei][ic]; + real64 const dCompAmount_dP = stack.dPoreVolume_dPres * m_compDens[ei][ic]; + stack.localJacobian[ic][0] += dCompAmount_dP; + + real64 const dCompAmount_dC = stack.poreVolume; + stack.localJacobian[ic][ic + 1] += dCompAmount_dC; + } + } + else + { + using Deriv = constitutive::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 = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; + + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; + arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; + + // temporary work arrays + real64 dPhaseAmount_dC[numComp]{}; + real64 dPhaseCompFrac_dC[numComp]{}; + + // start with old time step values + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localResidual[ic] = -m_compAmount_n[ei][ic]; + } + + // sum contributions to component accumulation from each phase + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + real64 const phaseAmount = stack.poreVolume * phaseVolFrac[ip] * phaseDens[ip]; + + real64 const dPhaseAmount_dP = stack.dPoreVolume_dPres * phaseVolFrac[ip] * phaseDens[ip] + + stack.poreVolume * ( 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.poreVolume; + } + + // 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 dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic] + + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dP]; + + stack.localResidual[ic] += phaseCompAmount; + 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, dPhaseAmount_dP, dPhaseAmount_dC ); + + } + } + } + + /** + * @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 = constitutive::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 + phaseVolFractionSumKernelOp( oneMinusPhaseVolFracSum ); + + // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations) + stack.localResidual[numComp] = stack.poreVolume * oneMinusPhaseVolFracSum; + for( integer idof = 0; idof < numDof; ++idof ) + { + stack.localJacobian[numComp][idof] *= stack.poreVolume; + } + stack.localJacobian[numComp][0] += stack.dPoreVolume_dPres * oneMinusPhaseVolFracSum; + } + + /** + * @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( KernelFlags::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; + 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; + arrayView3d< real64 const, compflow::USD_PHASE_DC > const m_dPhaseVolFrac; + + /// Views on the phase densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const m_dPhaseDens; + + /// Views on the phase component fraction + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const m_phaseCompFrac; + arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > const m_dPhaseCompFrac; + + // View on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + + // View on component amount (mass/moles) from previous time step + arrayView2d< real64 const, compflow::USD_COMP > m_compAmount_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< KernelFlags > const m_kernelFlags; +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +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[in] solid the solid model + * @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, + integer const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + integer const useSimpleAccumulation, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + internal::kernelLaunchSelectorCompSwitch( numComps, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC()+1; + + BitFlags< KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + if( useSimpleAccumulation ) + kernelFlags.set( KernelFlags::SimpleAccumulation ); + + AccumulationKernel< NUM_COMP, NUM_DOF > kernel( numPhases, rankOffset, dofKey, subRegion, + fluid, solid, localMatrix, localRhs, kernelFlags ); + AccumulationKernel< NUM_COMP, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.cpp new file mode 100644 index 00000000000..36ea1aa3226 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.cpp @@ -0,0 +1,268 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AquiferBCKernel.cpp + */ + +#include "physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "finiteVolume/BoundaryStencil.hpp" + +namespace geos +{ +using namespace constitutive; + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** AquiferBCKernel ********************************/ + +template< integer NC > +GEOS_HOST_DEVICE +void +AquiferBCKernel:: + compute( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + real64 const aquiferVolFlux, + real64 const dAquiferVolFlux_dPres, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens, + arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, + arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, + arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, + real64 const dt, + real64 (& localFlux)[NC], + real64 (& localFluxJacobian)[NC][NC+1] ) +{ + using Deriv = multifluid::DerivativeOffset; + + real64 dProp_dC[NC]{}; + real64 dPhaseFlux_dCompDens[NC]{}; + + if( aquiferVolFlux > 0 ) // aquifer is upstream + { + // in this case, we assume that: + // - only the water phase is present in the aquifer + // - the aquifer water phase composition is constant + + for( integer ic = 0; ic < NC; ++ic ) + { + real64 const phaseFlux = aquiferVolFlux * aquiferWaterPhaseDens; + localFlux[ic] -= dt * phaseFlux * aquiferWaterPhaseCompFrac[ic]; + localFluxJacobian[ic][0] -= dt * dAquiferVolFlux_dPres * aquiferWaterPhaseDens * aquiferWaterPhaseCompFrac[ic]; + } + } + else // reservoir is upstream + { + for( integer ip = 0; ip < numPhases; ++ip ) + { + + // Why two options below: + // - The aquifer model assumes single-phase water flow, so ideally, we should only allow water phase flow from the reservoir to the + // aquifer + // - But, if/when the CO2 plume reaches the reservoir cell connected to the aquifer and saturates it, the aquifer flux becomes zero + // if we don't let some CO2 go into the aquifer + + if( ip == ipWater || allowAllPhasesIntoAquifer ) + { + real64 const phaseDensVolFrac = phaseDens[ip] * phaseVolFrac[ip]; + real64 const phaseFlux = aquiferVolFlux * phaseDensVolFrac; + real64 const dPhaseFlux_dPres = dAquiferVolFlux_dPres * phaseDensVolFrac + + aquiferVolFlux * ( dPhaseDens[ip][Deriv::dP] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dP] ); + + applyChainRule( NC, dCompFrac_dCompDens, dPhaseDens[ip], dProp_dC, Deriv::dC ); + for( integer ic = 0; ic < NC; ++ic ) + { + dPhaseFlux_dCompDens[ic] = aquiferVolFlux * ( dProp_dC[ic] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+ic] ); + } + + for( integer ic = 0; ic < NC; ++ic ) + { + localFlux[ic] -= dt * phaseFlux * phaseCompFrac[ip][ic]; + localFluxJacobian[ic][0] -= dt * ( dPhaseFlux_dPres * phaseCompFrac[ip][ic] + phaseFlux * dPhaseCompFrac[ip][ic][Deriv::dP] ); + + applyChainRule( NC, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dProp_dC, Deriv::dC ); + for( integer jc = 0; jc < NC; ++jc ) + { + localFluxJacobian[ic][jc+1] -= dt * ( dPhaseFlux_dCompDens[jc] * phaseCompFrac[ip][ic] + phaseFlux * dProp_dC[jc] ); + } + } + } + } + } +} + +template< integer NC > +void +AquiferBCKernel:: + launch( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + integer const useTotalMassEquation, + BoundaryStencil const & stencil, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & presOld, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + real64 const timeAtBeginningOfStep, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) +{ + + using namespace compositionalMultiphaseUtilities; + using Order = BoundaryStencil::Order; + + BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); + BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); + + forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + constexpr integer NDOF = NC + 1; + + // working arrays + globalIndex dofColIndices[NDOF]{}; + real64 localFlux[NC]{}; + real64 localFluxJacobian[NC][NDOF]{}; + + localIndex const er = seri( iconn, Order::ELEM ); + localIndex const esr = sesri( iconn, Order::ELEM ); + localIndex const ei = sefi( iconn, Order::ELEM ); + real64 const areaFraction = weight( iconn, Order::ELEM ); + + // compute the aquifer influx rate using the pressure influence function and the aquifer props + real64 dAquiferVolFlux_dPres = 0.0; + real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, + dt, + pres[er][esr][ei], + presOld[er][esr][ei], + gravCoef[er][esr][ei], + areaFraction, + dAquiferVolFlux_dPres ); + + // compute the phase/component aquifer flux + AquiferBCKernel::compute< NC >( numPhases, + ipWater, + allowAllPhasesIntoAquifer, + aquiferVolFlux, + dAquiferVolFlux_dPres, + aquiferWaterPhaseDens, + aquiferWaterPhaseCompFrac, + phaseDens[er][esr][ei][0], + dPhaseDens[er][esr][ei][0], + phaseVolFrac[er][esr][ei], + dPhaseVolFrac[er][esr][ei], + phaseCompFrac[er][esr][ei][0], + dPhaseCompFrac[er][esr][ei][0], + dCompFrac_dCompDens[er][esr][ei], + dt, + localFlux, + localFluxJacobian ); + + // populate dof indices + globalIndex const offset = dofNumber[er][esr][ei]; + for( integer jdof = 0; jdof < NDOF; ++jdof ) + { + dofColIndices[jdof] = offset + jdof; + } + + if( useTotalMassEquation > 0 ) + { + // Apply equation/variable change transformation(s) + real64 work[NDOF]; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NDOF, localFluxJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, localFlux ); + } + + // Add to residual/jacobian + if( ghostRank[er][esr][ei] < 0 ) + { + globalIndex const globalRow = dofNumber[er][esr][ei]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( localMatrix.numRows(), localRow + NC ); + + for( integer ic = 0; ic < NC; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow + ic], localFlux[ic] ); + localMatrix.addToRow< parallelDeviceAtomic >( localRow + ic, + dofColIndices, + localFluxJacobian[ic], + NDOF ); + } + } + } ); +} + +#define INST_AquiferBCKernel( NC ) \ + template \ + void AquiferBCKernel:: \ + launch< NC >( integer const numPhases, \ + integer const ipWater, \ + bool const allowAllPhasesIntoAquifer, \ + integer const useTotalMassEquation, \ + BoundaryStencil const & stencil, \ + globalIndex const rankOffset, \ + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, \ + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, \ + real64 const aquiferWaterPhaseDens, \ + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, \ + ElementViewConst< arrayView1d< integer const > > const & ghostRank, \ + ElementViewConst< arrayView1d< real64 const > > const & pres, \ + ElementViewConst< arrayView1d< real64 const > > const & dPres, \ + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, \ + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, \ + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, \ + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, \ + ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, \ + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, \ + ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, \ + ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, \ + real64 const timeAtBeginningOfStep, \ + real64 const dt, \ + CRSMatrixView< real64, globalIndex const > const & localMatrix, \ + arrayView1d< real64 > const & localRhs ) + +INST_AquiferBCKernel( 1 ); +INST_AquiferBCKernel( 2 ); +INST_AquiferBCKernel( 3 ); +INST_AquiferBCKernel( 4 ); +INST_AquiferBCKernel( 5 ); + +#undef INST_AquiferBCKernel + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp new file mode 100644 index 00000000000..b1729589b30 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp @@ -0,0 +1,131 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AquiferBCKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_AQUIFERBCKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_AQUIFERBCKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "fieldSpecification/AquiferBoundaryCondition.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** AquiferBCKernel ********************************/ + +/** + * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian + */ +struct AquiferBCKernel +{ + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using CompFlowAccessors = + StencilAccessors< fields::ghostRank, + fields::flow::pressure, + fields::flow::pressure_n, + fields::flow::gravityCoefficient, + fields::flow::phaseVolumeFraction, + fields::flow::dPhaseVolumeFraction, + fields::flow::dGlobalCompFraction_dGlobalCompDensity >; + + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseDensity, + fields::multifluid::dPhaseDensity, + fields::multifluid::phaseCompFraction, + fields::multifluid::dPhaseCompFraction >; + + template< integer NC > + GEOS_HOST_DEVICE + inline + static void + compute( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + real64 const aquiferVolFlux, + real64 const dAquiferVolFlux_dPres, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens, + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, + arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, + real64 const dt, + real64 ( &localFlux )[NC], + real64 ( &localFluxJacobian )[NC][NC+1] ); + + template< integer NC > + static void + launch( integer const numPhases, + integer const ipWater, + bool const allowAllPhasesIntoAquifer, + integer const useTotalMassEquation, + BoundaryStencil const & stencil, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + real64 const aquiferWaterPhaseDens, + arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & pres_n, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + real64 const timeAtBeginningOfStep, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ); + +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_AQUIFERBCKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp new file mode 100644 index 00000000000..a254aa9f97d --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp @@ -0,0 +1,228 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file C1PPUPhaseFlux.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_C1PPUPHASEFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_C1PPUPHASEFLUX_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +// TODO make input parameter +static constexpr real64 epsC1PPU = 5000; + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct C1PPUPhaseFlux +{ + /** + * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head + * @tparam numComp number of components + * @tparam numFluxSupportPoints number of flux support points + * @param numPhase number of phases + * @param ip phase index + * @param hasCapPressure flag indicating if there is capillary pressure + * @param seri arraySlice of the stencil-implied element region index + * @param sesri arraySlice of the stencil-implied element subregion index + * @param sei arraySlice of the stencil-implied element index + * @param trans transmissibility at the connection + * @param dTrans_dPres derivative of transmissibility wrt pressure + * @param pres pressure + * @param gravCoef gravitational coefficient + * @param phaseMob phase mobility + * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density + * @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 phaseCapPressure phase capillary pressure + * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction + * @param k_up uptream index for this phase + * @param potGrad potential gradient for this phase + * @param phaseFlux phase flux + * @param dPhaseFlux_dP derivative of phase flux wrt pressure + * @param dPhaseFlux_dC derivative of phase flux wrt comp density + */ + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute( integer const numPhase, + integer const ip, + integer const hasCapPressure, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + real64 const ( &trans )[2], + real64 const ( &dTrans_dPres )[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + localIndex & k_up, + real64 & potGrad, + real64 ( &phaseFlux ), + real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], + real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp], + real64 ( & compFlux )[numComp], + real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], + real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) + { + real64 dPresGrad_dP[numFluxSupportPoints]{}; + real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; + real64 dGravHead_dP[numFluxSupportPoints]{}; + real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; + PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, seri, sesri, sei, trans, dTrans_dPres, pres, + gravCoef, phaseVolFrac, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, + phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, + dPresGrad_dC, dGravHead_dP, dGravHead_dC ); + + // gravity head + real64 gravHead = 0.0; + 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 = Ttrans * ( 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]; + } + } + + potGrad = potGrad * Ttrans; + + // choose upstream cell for composition upwinding + k_up = (phaseFlux >= 0) ? 0 : 1; + + //distribute on phaseComponentFlux here + PhaseComponentFlux::compute( ip, k_up, seri, sesri, sei, phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, phaseFlux + , dPhaseFlux_dP, dPhaseFlux_dC, compFlux, dCompFlux_dP, dCompFlux_dC ); + } +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_C1PPUPHASEFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp similarity index 58% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.cpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp index ebceae552f0..b416573af0b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp @@ -14,17 +14,14 @@ */ /** - * @file IsothermalCompositionalMultiphaseFVMKernels.cpp + * @file CFLKernel.cpp */ -#include "IsothermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" - +#include "physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp" #include "finiteVolume/CellElementStencilTPFA.hpp" #include "finiteVolume/SurfaceElementStencil.hpp" #include "finiteVolume/EmbeddedSurfaceToCellStencil.hpp" #include "finiteVolume/FaceElementToCellStencil.hpp" -#include "mesh/utilities/MeshMapUtilities.hpp" namespace geos { @@ -33,34 +30,6 @@ using namespace constitutive; namespace isothermalCompositionalMultiphaseFVMKernels { -/******************************** FaceBasedAssemblyKernel ********************************/ - -FaceBasedAssemblyKernelBase::FaceBasedAssemblyKernelBase( integer const numPhases, - globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< FaceBasedAssemblyKernelFlags > kernelFlags ) - : m_numPhases( numPhases ), - m_rankOffset( rankOffset ), - m_dt( dt ), - m_dofNumber( dofNumberAccessor.toNestedViewConst() ), - m_ghostRank( compFlowAccessors.get( fields::ghostRank {} ) ), - m_gravCoef( compFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), - m_pres( compFlowAccessors.get( fields::flow::pressure {} ) ), - m_phaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} ) ), - m_dPhaseVolFrac( compFlowAccessors.get( fields::flow::dPhaseVolumeFraction {} ) ), - m_dCompFrac_dCompDens( compFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity {} ) ), - m_phaseCompFrac( multiFluidAccessors.get( fields::multifluid::phaseCompFraction {} ) ), - m_dPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::dPhaseCompFraction {} ) ), - m_localMatrix( localMatrix ), - m_localRhs( localRhs ), - m_kernelFlags( kernelFlags ) -{} - /******************************** CFLFluxKernel ********************************/ template< integer NC, localIndex NUM_ELEMS, localIndex maxStencilSize > @@ -470,241 +439,6 @@ INST_CFLKernel( 5, 3 ); #undef INST_CFLKernel -/******************************** AquiferBCKernel ********************************/ - -template< integer NC > -GEOS_HOST_DEVICE -void -AquiferBCKernel:: - compute( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - real64 const aquiferVolFlux, - real64 const dAquiferVolFlux_dPres, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseDens, - arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseDens, - arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, - arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac, - arraySlice2d< real64 const, multifluid::USD_PHASE_COMP - 2 > phaseCompFrac, - arraySlice3d< real64 const, multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac, - arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens, - real64 const dt, - real64 (& localFlux)[NC], - real64 (& localFluxJacobian)[NC][NC+1] ) -{ - using Deriv = multifluid::DerivativeOffset; - - real64 dProp_dC[NC]{}; - real64 dPhaseFlux_dCompDens[NC]{}; - - if( aquiferVolFlux > 0 ) // aquifer is upstream - { - // in this case, we assume that: - // - only the water phase is present in the aquifer - // - the aquifer water phase composition is constant - - for( integer ic = 0; ic < NC; ++ic ) - { - real64 const phaseFlux = aquiferVolFlux * aquiferWaterPhaseDens; - localFlux[ic] -= dt * phaseFlux * aquiferWaterPhaseCompFrac[ic]; - localFluxJacobian[ic][0] -= dt * dAquiferVolFlux_dPres * aquiferWaterPhaseDens * aquiferWaterPhaseCompFrac[ic]; - } - } - else // reservoir is upstream - { - for( integer ip = 0; ip < numPhases; ++ip ) - { - - // Why two options below: - // - The aquifer model assumes single-phase water flow, so ideally, we should only allow water phase flow from the reservoir to the - // aquifer - // - But, if/when the CO2 plume reaches the reservoir cell connected to the aquifer and saturates it, the aquifer flux becomes zero - // if we don't let some CO2 go into the aquifer - - if( ip == ipWater || allowAllPhasesIntoAquifer ) - { - real64 const phaseDensVolFrac = phaseDens[ip] * phaseVolFrac[ip]; - real64 const phaseFlux = aquiferVolFlux * phaseDensVolFrac; - real64 const dPhaseFlux_dPres = dAquiferVolFlux_dPres * phaseDensVolFrac - + aquiferVolFlux * ( dPhaseDens[ip][Deriv::dP] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dP] ); - - applyChainRule( NC, dCompFrac_dCompDens, dPhaseDens[ip], dProp_dC, Deriv::dC ); - for( integer ic = 0; ic < NC; ++ic ) - { - dPhaseFlux_dCompDens[ic] = aquiferVolFlux * ( dProp_dC[ic] * phaseVolFrac[ip] + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC+ic] ); - } - - for( integer ic = 0; ic < NC; ++ic ) - { - localFlux[ic] -= dt * phaseFlux * phaseCompFrac[ip][ic]; - localFluxJacobian[ic][0] -= dt * ( dPhaseFlux_dPres * phaseCompFrac[ip][ic] + phaseFlux * dPhaseCompFrac[ip][ic][Deriv::dP] ); - - applyChainRule( NC, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dProp_dC, Deriv::dC ); - for( integer jc = 0; jc < NC; ++jc ) - { - localFluxJacobian[ic][jc+1] -= dt * ( dPhaseFlux_dCompDens[jc] * phaseCompFrac[ip][ic] + phaseFlux * dProp_dC[jc] ); - } - } - } - } - } -} - -template< integer NC > -void -AquiferBCKernel:: - launch( integer const numPhases, - integer const ipWater, - bool const allowAllPhasesIntoAquifer, - integer const useTotalMassEquation, - BoundaryStencil const & stencil, - globalIndex const rankOffset, - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - real64 const aquiferWaterPhaseDens, - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, - ElementViewConst< arrayView1d< integer const > > const & ghostRank, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & presOld, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - real64 const timeAtBeginningOfStep, - real64 const dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) -{ - - using namespace compositionalMultiphaseUtilities; - using Order = BoundaryStencil::Order; - - BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); - BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); - - forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - constexpr integer NDOF = NC + 1; - - // working arrays - globalIndex dofColIndices[NDOF]{}; - real64 localFlux[NC]{}; - real64 localFluxJacobian[NC][NDOF]{}; - - localIndex const er = seri( iconn, Order::ELEM ); - localIndex const esr = sesri( iconn, Order::ELEM ); - localIndex const ei = sefi( iconn, Order::ELEM ); - real64 const areaFraction = weight( iconn, Order::ELEM ); - - // compute the aquifer influx rate using the pressure influence function and the aquifer props - real64 dAquiferVolFlux_dPres = 0.0; - real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, - dt, - pres[er][esr][ei], - presOld[er][esr][ei], - gravCoef[er][esr][ei], - areaFraction, - dAquiferVolFlux_dPres ); - - // compute the phase/component aquifer flux - AquiferBCKernel::compute< NC >( numPhases, - ipWater, - allowAllPhasesIntoAquifer, - aquiferVolFlux, - dAquiferVolFlux_dPres, - aquiferWaterPhaseDens, - aquiferWaterPhaseCompFrac, - phaseDens[er][esr][ei][0], - dPhaseDens[er][esr][ei][0], - phaseVolFrac[er][esr][ei], - dPhaseVolFrac[er][esr][ei], - phaseCompFrac[er][esr][ei][0], - dPhaseCompFrac[er][esr][ei][0], - dCompFrac_dCompDens[er][esr][ei], - dt, - localFlux, - localFluxJacobian ); - - // populate dof indices - globalIndex const offset = dofNumber[er][esr][ei]; - for( integer jdof = 0; jdof < NDOF; ++jdof ) - { - dofColIndices[jdof] = offset + jdof; - } - - if( useTotalMassEquation > 0 ) - { - // Apply equation/variable change transformation(s) - real64 work[NDOF]; - shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( NC, NDOF, localFluxJacobian, work ); - shiftElementsAheadByOneAndReplaceFirstElementWithSum( NC, localFlux ); - } - - // Add to residual/jacobian - if( ghostRank[er][esr][ei] < 0 ) - { - globalIndex const globalRow = dofNumber[er][esr][ei]; - localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); - GEOS_ASSERT_GE( localRow, 0 ); - GEOS_ASSERT_GT( localMatrix.numRows(), localRow + NC ); - - for( integer ic = 0; ic < NC; ++ic ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow + ic], localFlux[ic] ); - localMatrix.addToRow< parallelDeviceAtomic >( localRow + ic, - dofColIndices, - localFluxJacobian[ic], - NDOF ); - } - } - } ); -} - -#define INST_AquiferBCKernel( NC ) \ - template \ - void AquiferBCKernel:: \ - launch< NC >( integer const numPhases, \ - integer const ipWater, \ - bool const allowAllPhasesIntoAquifer, \ - integer const useTotalMassEquation, \ - BoundaryStencil const & stencil, \ - globalIndex const rankOffset, \ - ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, \ - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, \ - real64 const aquiferWaterPhaseDens, \ - arrayView1d< real64 const > const & aquiferWaterPhaseCompFrac, \ - ElementViewConst< arrayView1d< integer const > > const & ghostRank, \ - ElementViewConst< arrayView1d< real64 const > > const & pres, \ - ElementViewConst< arrayView1d< real64 const > > const & dPres, \ - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, \ - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, \ - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, \ - ElementViewConst< arrayView3d< real64 const, multifluid::USD_PHASE > > const & phaseDens, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_DC > > const & dPhaseDens, \ - ElementViewConst< arrayView4d< real64 const, multifluid::USD_PHASE_COMP > > const & phaseCompFrac, \ - ElementViewConst< arrayView5d< real64 const, multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, \ - real64 const timeAtBeginningOfStep, \ - real64 const dt, \ - CRSMatrixView< real64, globalIndex const > const & localMatrix, \ - arrayView1d< real64 > const & localRhs ) - -INST_AquiferBCKernel( 1 ); -INST_AquiferBCKernel( 2 ); -INST_AquiferBCKernel( 3 ); -INST_AquiferBCKernel( 4 ); -INST_AquiferBCKernel( 5 ); - -#undef INST_AquiferBCKernel - } // namespace isothermalCompositionalMultiphaseFVMKernels } // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp new file mode 100644 index 00000000000..8449d57e43e --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp @@ -0,0 +1,184 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CFLKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CFLKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CFLKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/permeability/PermeabilityBase.hpp" +#include "constitutive/permeability/PermeabilityFields.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** CFLFluxKernel ********************************/ + +/** + * @brief Functions to compute the (outflux) total volumetric flux needed in the calculation of CFL numbers + */ +struct CFLFluxKernel +{ + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + template< typename VIEWTYPE > + using ElementView = ElementRegionManager::ElementView< VIEWTYPE >; + + using CompFlowAccessors = + StencilAccessors< fields::flow::pressure, + fields::flow::gravityCoefficient, + fields::flow::phaseVolumeFraction, + fields::flow::phaseOutflux, + fields::flow::componentOutflux >; + + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseViscosity, + fields::multifluid::phaseDensity, + fields::multifluid::phaseMassDensity, + fields::multifluid::phaseCompFraction >; + + using PermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure >; + + + using RelPermAccessors = + StencilMaterialAccessors< constitutive::RelativePermeabilityBase, fields::relperm::phaseRelPerm >; + + template< integer NC, localIndex NUM_ELEMS, localIndex maxStencilSize > + GEOS_HOST_DEVICE + inline + static void + compute( integer const numPhases, + localIndex const stencilSize, + real64 const dt, + arraySlice1d< localIndex const > const seri, + arraySlice1d< localIndex const > const sesri, + arraySlice1d< localIndex const > const sei, + real64 const (&transmissibility)[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const & phaseRelPerm, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseVisc, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, + ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); + + template< integer NC, typename STENCILWRAPPER_TYPE > + static void + launch( integer const numPhases, + real64 const dt, + STENCILWRAPPER_TYPE const & stencil, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const > > const & permeability, + ElementViewConst< arrayView3d< real64 const > > const & dPerm_dPres, + ElementViewConst< arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > > const & phaseRelPerm, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseVisc, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementView< arrayView2d< real64, compflow::USD_PHASE > > const & phaseOutflux, + ElementView< arrayView2d< real64, compflow::USD_COMP > > const & compOutflux ); +}; + +/******************************** CFLKernel ********************************/ + +/** + * @brief Functions to compute the CFL number using the phase volumetric outflux and the component mass outflux in each cell + */ +struct CFLKernel +{ + + static constexpr real64 minPhaseMobility = 1e-12; + static constexpr real64 minComponentFraction = 1e-12; + + template< integer NP > + GEOS_HOST_DEVICE + inline + static void + computePhaseCFL( real64 const poreVol, + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac, + arraySlice1d< real64 const, constitutive::relperm::USD_RELPERM - 2 > phaseRelPerm, + arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > dPhaseRelPerm_dPhaseVolFrac, + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseVisc, + arraySlice1d< real64 const, compflow::USD_PHASE- 1 > phaseOutflux, + real64 & phaseCFLNumber ); + + template< integer NC > + GEOS_HOST_DEVICE + inline + static void + computeCompCFL( real64 const poreVol, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compDens, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compFrac, + arraySlice1d< real64 const, compflow::USD_COMP - 1 > compOutflux, + real64 & compCFLNumber ); + + template< integer NC, integer NP > + static void + launch( localIndex const size, + arrayView1d< real64 const > const & volume, + arrayView2d< real64 const > const & porosity, + arrayView2d< real64 const, compflow::USD_COMP > const & compDens, + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseRelPerm, + arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > const & dPhaseRelPerm_dPhaseVolFrac, + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseVisc, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseOutflux, + arrayView2d< real64 const, compflow::USD_COMP > const & compOutflux, + arrayView1d< real64 > const & phaseCFLNumber, + arrayView1d< real64 > const & compCFLNumber, + real64 & maxPhaseCFLNumber, + real64 & maxCompCFLNumber ); + +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CFLKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp new file mode 100644 index 00000000000..7842c859189 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp @@ -0,0 +1,73 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CapillaryPressureUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CAPILLARYPRESSUREUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CAPILLARYPRESSUREUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** CapillaryPressureUpdateKernel ********************************/ + +struct CapillaryPressureUpdateKernel +{ + template< typename POLICY, typename CAPPRES_WRAPPER > + static void + launch( localIndex const size, + CAPPRES_WRAPPER const & capPresWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) + { + capPresWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } + + template< typename POLICY, typename CAPPRES_WRAPPER > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + CAPPRES_WRAPPER const & capPresWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + localIndex const k = targetSet[a]; + for( localIndex q = 0; q < capPresWrapper.numGauss(); ++q ) + { + capPresWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_CAPILLARYPRESSUREUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.cpp similarity index 100% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.cpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.cpp diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp similarity index 99% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp index eb147ed4e92..c388cad6da5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/CompositionalMultiphaseHybridFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp @@ -30,9 +30,12 @@ #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "mesh/ElementRegionManager.hpp" #include "mesh/ObjectManagerBase.hpp" +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp new file mode 100644 index 00000000000..ac5ab4265da --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp @@ -0,0 +1,775 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file DiffusionDispersionFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/diffusion/DiffusionFields.hpp" +#include "constitutive/diffusion/DiffusionBase.hpp" +#include "constitutive/dispersion/DispersionFields.hpp" +#include "constitutive/dispersion/DispersionBase.hpp" +#include "constitutive/solid/porosity/PorosityBase.hpp" +#include "constitutive/solid/porosity/PorosityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DiffusionDispersionFluxComputeKernel ********************************/ + +/** + * @class DiffusionDispersionFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class DiffusionDispersionFluxComputeKernel : public FluxComputeKernelBase +{ +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 (all of them, except the volume balance equation) + static constexpr integer numEqn = NUM_DOF-1; + + /// Maximum number of elements at the face + static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; + + /// Maximum number of connections at the face + static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; + + /// Maximum number of points in the stencil + static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; + + /// Number of flux support points (hard-coded for TFPA) + static constexpr integer numFluxSupportPoints = 2; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using AbstractBase::m_dPhaseVolFrac; + using AbstractBase::m_kernelFlags; + + using DiffusionAccessors = + StencilMaterialAccessors< constitutive::DiffusionBase, + fields::diffusion::diffusivity, + fields::diffusion::dDiffusivity_dTemperature, + fields::diffusion::phaseDiffusivityMultiplier >; + + using DispersionAccessors = + StencilMaterialAccessors< constitutive::DispersionBase, + fields::dispersion::dispersivity >; + + using PorosityAccessors = + StencilMaterialAccessors< constitutive::PorosityBase, + fields::porosity::referencePorosity >; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @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] diffusionAccessors + * @param[in] dispersionAccessors + * @param[in] porosityAccessors + * @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 + */ + DiffusionDispersionFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + DiffusionAccessors const & diffusionAccessors, + DispersionAccessors const & dispersionAccessors, + PorosityAccessors const & porosityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : FluxComputeKernelBase( numPhases, + rankOffset, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_phaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} ) ), + m_phaseDens( multiFluidAccessors.get( fields::multifluid::phaseDensity {} ) ), + m_dPhaseDens( multiFluidAccessors.get( fields::multifluid::dPhaseDensity {} ) ), + m_diffusivity( diffusionAccessors.get( fields::diffusion::diffusivity {} ) ), + m_dDiffusivity_dTemp( diffusionAccessors.get( fields::diffusion::dDiffusivity_dTemperature {} ) ), + m_phaseDiffusivityMultiplier( diffusionAccessors.get( fields::diffusion::phaseDiffusivityMultiplier {} ) ), + m_dispersivity( dispersionAccessors.get( fields::dispersion::dispersivity {} ) ), + m_referencePorosity( porosityAccessors.get( fields::porosity::referencePorosity {} ) ), + m_stencilWrapper( stencilWrapper ), + m_seri( stencilWrapper.getElementRegionIndices() ), + m_sesri( stencilWrapper.getElementSubRegionIndices() ), + m_sei( stencilWrapper.getElementIndices() ) + { } + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + 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, localIndex numElems ) + : stencilSize( size ), + numConnectedElems( numElems ), + dofColIndices( size * numDof ), + localFlux( numElems * numEqn ), + localFluxJacobian( numElems * numEqn, size * numDof ) + {} + + // Stencil information + + /// Stencil size for a given connection + localIndex const stencilSize; + /// Number of elements connected at a given connection + localIndex const numConnectedElems; + + /// Transmissibility + real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; + /// Derivatives of transmissibility with respect to pressure + real64 dTrans_dTemp[maxNumConns][numFluxSupportPoints]{}; + + // 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 equations except volume balance) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; + }; + + + /** + * @brief Getter for the stencil size at this connection + * @param[in] iconn the connection index + * @return the size of the stencil at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex stencilSize( localIndex const iconn ) const + { return m_sei[iconn].size(); } + + /** + * @brief Getter for the number of elements at this connection + * @param[in] iconn the connection index + * @return the number of elements at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex numPointsInFlux( localIndex const iconn ) const + { return m_stencilWrapper.numPointsInFlux( iconn ); } + + + /** + * @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 + { + // set degrees of freedom indices for this face + for( integer i = 0; i < stack.stencilSize; ++i ) + { + globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[i * numDof + jdof] = offset + jdof; + } + } + } + + /** + * @brief Compute the local diffusion 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] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] diffusionFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeDiffusionFlux( localIndex const iconn, + StackVariables & stack, + FUNC && diffusionFluxKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // first, compute the transmissibilities at this face + m_stencilWrapper.computeWeights( iconn, + m_diffusivity, + m_dDiffusivity_dTemp, + stack.transmissibility, + stack.dTrans_dTemp ); + + + localIndex k[numFluxSupportPoints]{}; + localIndex connectionIndex = 0; + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + /// cell indices + localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + // clear working arrays + real64 diffusionFlux[numComp]{}; + real64 dDiffusionFlux_dP[numFluxSupportPoints][numComp]{}; + real64 dDiffusionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; + real64 dDens_dC[numComp]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + //***** calculation of flux ***** + // loop over phases, compute and upwind phase flux and sum contributions to each component's flux + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + + // loop over components + for( integer ic = 0; ic < numComp; ++ic ) + { + + real64 compFracGrad = 0.0; + real64 dCompFracGrad_dP[numFluxSupportPoints]{}; + real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; + + // compute the component fraction gradient using the diffusion transmissibility + computeCompFractionGradient( ip, ic, + seri, sesri, sei, + trans, + compFracGrad, + dCompFracGrad_dP, + dCompFracGrad_dC ); + + // choose upstream cell for composition upwinding + localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; + + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + // computation of the upwinded mass flux + real64 const upwindCoefficient = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_phaseVolFrac[er_up][esr_up][ei_up][ip]; + diffusionFlux[ic] += upwindCoefficient * compFracGrad; + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) + { + dDiffusionFlux_dP[ke][ic] += upwindCoefficient * dCompFracGrad_dP[ke]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDiffusionFlux_dC[ke][ic][jc] += upwindCoefficient * dCompFracGrad_dC[ke][jc]; + } + } + + // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions + real64 const dUpwindCoefficient_dP = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] + + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dP] ); + dDiffusionFlux_dP[k_up][ic] += dUpwindCoefficient_dP * compFracGrad; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er_up][esr_up][ei_up], + m_dPhaseDens[er_up][esr_up][ei_up][0][ip], + dDens_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + real64 const dUpwindCoefficient_dC = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + ( dDens_dC[jc] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] + + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dC+jc] ); + dDiffusionFlux_dC[k_up][ic][jc] += dUpwindCoefficient_dC * compFracGrad; + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + diffusionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, + k_up, seri[k_up], sesri[k_up], sei[k_up], + compFracGrad, upwindCoefficient ); + + } // loop over components + } // loop over phases + + // add diffusion flux to local flux and local flux jacobian + addToLocalFluxAndJacobian( k, + stack, + diffusionFlux, + dDiffusionFlux_dP, + dDiffusionFlux_dC ); + + connectionIndex++; + } // loop over k[1] + } // loop over k[0] + } + + /** + * @brief Compute the local dispersion 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] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] dispersionFluxKernelOp the function used to customize the computation of the component fluxes + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void computeDispersionFlux( localIndex const iconn, + StackVariables & stack, + FUNC && dispersionFluxKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // first, compute the transmissibilities at this face + // note that the dispersion tensor is lagged in iteration + m_stencilWrapper.computeWeights( iconn, + m_dispersivity, + m_dispersivity, // this is just to pass something, but the resulting derivative won't be used + stack.transmissibility, + stack.dTrans_dTemp ); // will not be used + + + localIndex k[numFluxSupportPoints]{}; + localIndex connectionIndex = 0; + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + /// cell indices + localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + // clear working arrays + real64 dispersionFlux[numComp]{}; + real64 dDispersionFlux_dP[numFluxSupportPoints][numComp]{}; + real64 dDispersionFlux_dC[numFluxSupportPoints][numComp][numComp]{}; + real64 dDens_dC[numComp]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + //***** calculation of flux ***** + // loop over phases, compute and upwind phase flux and sum contributions to each component's flux + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + + // loop over components + for( integer ic = 0; ic < numComp; ++ic ) + { + + real64 compFracGrad = 0.0; + real64 dCompFracGrad_dP[numFluxSupportPoints]{}; + real64 dCompFracGrad_dC[numFluxSupportPoints][numComp]{}; + + // compute the component fraction gradient using the dispersion transmissibility + computeCompFractionGradient( ip, ic, + seri, sesri, sei, + trans, + compFracGrad, + dCompFracGrad_dP, + dCompFracGrad_dC ); + + // choose upstream cell for composition upwinding + localIndex const k_up = (compFracGrad >= 0) ? 0 : 1; + + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + // computation of the upwinded mass flux + dispersionFlux[ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * compFracGrad; + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ke++ ) + { + dDispersionFlux_dP[ke][ic] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dP[ke]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDispersionFlux_dC[ke][ic][jc] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dC[ke][jc]; + } + } + + // add contributions of the derivatives of upwind coefficient wrt pressure/component fractions + dDispersionFlux_dP[k_up][ic] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dP] * compFracGrad; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er_up][esr_up][ei_up], + m_dPhaseDens[er_up][esr_up][ei_up][0][ip], + dDens_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dDispersionFlux_dC[k_up][ic][jc] += dDens_dC[jc] * compFracGrad; + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + dispersionFluxKernelOp( ip, ic, k, seri, sesri, sei, connectionIndex, + k_up, seri[k_up], sesri[k_up], sei[k_up], + compFracGrad ); + + } // loop over components + } // loop over phases + + // add dispersion flux to local flux and local flux jacobian + addToLocalFluxAndJacobian( k, + stack, + dispersionFlux, + dDispersionFlux_dP, + dDispersionFlux_dC ); + + connectionIndex++; + } // loop over k[1] + } // loop over k[0] + } + + /** + * @brief Compute the component fraction gradient at this interface + * @param[in] ip the phase index + * @param[in] ic the component index + * @param[in] seri the region indices + * @param[in] sesri the subregion indices + * @param[in] sei the element indices + * @param[out] compFracGrad the component fraction gradient + * @param[out] dCompFracGrad_dP the derivatives of the component fraction gradient wrt pressure + * @param[out] dCompFracGrad_dC the derivatives of the component fraction gradient wrt component densities + */ + GEOS_HOST_DEVICE + inline + void computeCompFractionGradient( integer const ip, + integer const ic, + localIndex const (&seri)[numFluxSupportPoints], + localIndex const (&sesri)[numFluxSupportPoints], + localIndex const (&sei)[numFluxSupportPoints], + real64 const (&trans)[numFluxSupportPoints], + real64 & compFracGrad, + real64 (& dCompFracGrad_dP)[numFluxSupportPoints], + real64 (& dCompFracGrad_dC)[numFluxSupportPoints][numComp] ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + real64 dCompFrac_dC[numComp]{}; + + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + compFracGrad += trans[i] * m_phaseCompFrac[er][esr][ei][0][ip][ic]; + dCompFracGrad_dP[i] += trans[i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dP]; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + m_dPhaseCompFrac[er][esr][ei][0][ip][ic], + dCompFrac_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFracGrad_dC[i][jc] += trans[i] * dCompFrac_dC[jc]; + } + } + } + + /** + * @brief Add the local diffusion/dispersion flux contributions to the residual and Jacobian + * @param[in] k the cell indices + * @param[in] stack the stack variables + * @param[in] flux the diffusion/dispersion flux + * @param[in] dFlux_dP the derivative of the diffusion/dispersion flux wrt pressure + * @param[in] dFlux_dC the derivative of the diffusion/dispersion flux wrt compositions + */ + GEOS_HOST_DEVICE + inline + void addToLocalFluxAndJacobian( localIndex const (&k)[numFluxSupportPoints], + StackVariables & stack, + real64 const (&flux)[numComp], + real64 const (&dFlux_dP)[numFluxSupportPoints][numComp], + real64 const (&dFlux_dC)[numFluxSupportPoints][numComp][numComp] ) const + { + // loop over components + for( integer ic = 0; ic < numComp; ++ic ) + { + // finally, increment local flux and local Jacobian + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + stack.localFlux[eqIndex0] += m_dt * flux[ic]; + stack.localFlux[eqIndex1] -= m_dt * flux[ic]; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dFlux_dP[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dFlux_dP[ke][ic]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dFlux_dC[ke][ic][jc]; + stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dFlux_dC[ke][ic][jc]; + } + } + } + } + + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using namespace compositionalMultiphaseUtilities; + + if( m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) ) + { + // Apply equation/variable change transformation(s) + stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof*stack.stencilSize, stack.numConnectedElems, + stack.localFluxJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, + stack.localFlux ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + for( integer i = 0; i < stack.numConnectedElems; ++i ) + { + if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); + + for( integer ic = 0; ic < numComp; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], stack.localFlux[i * numEqn + ic] ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + ic, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), + stack.stencilSize * numDof ); + } + + // call the lambda to assemble additional terms, such as thermal terms + assemblyKernelOp( i, localRow ); + } + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numConnections the number of connections + * @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 numConnections, + integer const hasDiffusion, + integer const hasDispersion, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + kernelComponent.numPointsInFlux( iconn ) ); + + kernelComponent.setup( iconn, stack ); + if( hasDiffusion ) + { + kernelComponent.computeDiffusionFlux( iconn, stack ); + } + if( hasDispersion ) + { + kernelComponent.computeDispersionFlux( iconn, stack ); + } + kernelComponent.complete( iconn, stack ); + } ); + } + +protected: + + /// Views on phase volume fraction + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseVolFrac; + + /// Views on phase densities + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseDens; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseDens; + + /// Views on diffusivity + ElementViewConst< arrayView3d< real64 const > > const m_diffusivity; + ElementViewConst< arrayView3d< real64 const > > const m_dDiffusivity_dTemp; + ElementViewConst< arrayView3d< real64 const > > const m_phaseDiffusivityMultiplier; + + /// Views on dispersivity + ElementViewConst< arrayView3d< real64 const > > const m_dispersivity; + + /// View on the reference porosity + ElementViewConst< arrayView1d< real64 const > > const m_referencePorosity; + + // Stencil information + + /// Reference to the stencil wrapper + STENCILWRAPPER const m_stencilWrapper; + + /// Connection to element maps + typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; + +}; + +/** + * @class DiffusionDispersionFluxComputeKernelFactory + */ +class DiffusionDispersionFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @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 string to get the element degrees of freedom numbers + * @param[in] hasDiffusion flag specifying whether diffusion is used or not + * @param[in] hasDispersion flag specifying whether dispersion is used or not + * @param[in] solverName the name of the solver + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasDiffusion, + integer const hasDispersion, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + 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() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + + using kernelType = DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); + typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); + typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, stencilWrapper, + dofNumberAccessor, compFlowAccessors, multiFluidAccessors, + diffusionAccessors, dispersionAccessors, porosityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), + hasDiffusion, hasDispersion, + kernel ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..420d8538f1b --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp @@ -0,0 +1,558 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file DirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public FluxComputeKernel< NUM_COMP, + NUM_DOF, + BoundaryStencilWrapper > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_numPhases; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_ghostRank; + using AbstractBase::m_gravCoef; + using AbstractBase::m_pres; + using AbstractBase::m_phaseCompFrac; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dCompFrac_dCompDens; + using AbstractBase::m_localMatrix; + using AbstractBase::m_localRhs; + using AbstractBase::m_kernelFlags; + + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, BoundaryStencilWrapper >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::m_stencilWrapper; + using Base::m_phaseMob; + using Base::m_dPhaseMob; + using Base::m_phaseMassDens; + using Base::m_dPhaseMassDens; + using Base::m_permeability; + using Base::m_dPerm_dPres; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid 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 + */ + DirichletFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_facePres( faceManager.getField< fields::flow::facePressure >() ), + m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), + m_faceCompFrac( faceManager.getField< fields::flow::faceGlobalCompFraction >() ), + m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), + m_fluidWrapper( fluidWrapper ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + 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 GEOS_UNUSED_PARAM( size ), + localIndex GEOS_UNUSED_PARAM( numElems )) {} + + // Transmissibility + real64 transmissibility = 0.0; + + // Component fluxes and derivatives + + /// Component fluxes + real64 compFlux[numComp]{}; + /// Derivatives of component fluxes wrt pressure + real64 dCompFlux_dP[numComp]{}; + /// Derivatives of component fluxes wrt component densities + real64 dCompFlux_dC[numComp][numComp]{}; + + // Local degrees of freedom and local residual/jacobian + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + globalIndex dofColIndices[numDof]{}; + + /// Storage for the face local residual vector + real64 localFlux[numEqn]{}; + /// Storage for the face local Jacobian matrix + real64 localFluxJacobian[numEqn][numDof]{}; + + }; + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const iconn, + StackVariables & stack ) const + { + globalIndex const offset = + m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[jdof] = offset + jdof; + } + } + + + /** + * @brief Compute the local Dirichlet face 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] iconn the connection 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 + void computeFlux( localIndex const iconn, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + using Order = BoundaryStencil::Order; + + localIndex const er = m_seri( iconn, Order::ELEM ); + localIndex const esr = m_sesri( iconn, Order::ELEM ); + localIndex const ei = m_sei( iconn, Order::ELEM ); + localIndex const kf = m_sei( iconn, Order::FACE ); + + // Step 1: compute the transmissibility at the boundary face + + real64 dTrans_dPerm[3]{}; + m_stencilWrapper.computeWeights( iconn, + m_permeability, + stack.transmissibility, + dTrans_dPerm ); + real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); + + // Step 2: compute the fluid properties on the face + // This is needed to get the phase mass density and the phase comp fraction at the face + // Because we approximate the face mobility using the total element mobility + + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseFrac( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseDens( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseMassDens( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseVisc( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseEnthalpy( 1, 1, m_numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > facePhaseInternalEnergy( 1, 1, m_numPhases ); + StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES * NUM_COMP, + constitutive::multifluid::LAYOUT_PHASE_COMP > facePhaseCompFrac( 1, 1, m_numPhases, NUM_COMP ); + real64 faceTotalDens = 0.0; + + constitutive::MultiFluidBase::KernelWrapper::computeValues( m_fluidWrapper, + m_facePres[kf], + m_faceTemp[kf], + m_faceCompFrac[kf], + facePhaseFrac[0][0], + facePhaseDens[0][0], + facePhaseMassDens[0][0], + facePhaseVisc[0][0], + facePhaseEnthalpy[0][0], + facePhaseInternalEnergy[0][0], + facePhaseCompFrac[0][0], + faceTotalDens ); + + // Step 3: loop over phases, compute and upwind phase flux and sum contributions to each component's flux + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + + // working variables + real64 dDensMean_dC[numComp]{}; + real64 dF_dC[numComp]{}; + real64 dProp_dC[numComp]{}; + + real64 phaseFlux = 0.0; // for the lambda + real64 dPhaseFlux_dP = 0.0; + real64 dPhaseFlux_dC[numComp]{}; + + + // Step 3.1: compute the average phase mass density at the face + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + m_dPhaseMassDens[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + + // average density and derivatives + real64 const densMean = 0.5 * ( m_phaseMassDens[er][esr][ei][0][ip] + facePhaseMassDens[0][0][ip] ); + real64 const dDensMean_dP = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDensMean_dC[jc] = 0.5 * dProp_dC[jc]; + } + + + // Step 3.2: compute the (TPFA) potential difference at the face + + real64 const gravTimesDz = m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]; + real64 const potDif = m_pres[er][esr][ei] - m_facePres[kf] - densMean * gravTimesDz; + real64 const f = stack.transmissibility * potDif; + real64 const dF_dP = stack.transmissibility * ( 1.0 - dDensMean_dP * gravTimesDz ) + dTrans_dPres * potDif; + for( integer jc = 0; jc < numComp; ++jc ) + { + dF_dC[jc] = -stack.transmissibility * dDensMean_dC[jc] * gravTimesDz; + } + + // Step 3.3: computation of the mobility + // We do that before the if/else statement to be able to pass it to the compFluxOpKernel + + // recomputing the exact mobility at the face would be quite complex, as it would require: + // 1) computing the saturation + // 2) computing the relperm + // 3) computing the mobility as \lambda_p = \rho_p kr_p( S_p ) / \mu_p + // the second step in particular would require yet another dispatch to get the relperm model + // so, for simplicity, we approximate the face mobility as + // \lambda^approx_p = \rho_p S_p / \mu_p + // = \rho_p ( (nu_p / rho_p) * rho_t ) / \mu_p (plugging the expression of saturation) + // = \nu_p * rho_t / \mu_p + // fortunately, we don't need the derivatives + real64 const facePhaseMob = ( facePhaseFrac[0][0][ip] > 0.0 ) + ? facePhaseFrac[0][0][ip] * faceTotalDens / facePhaseVisc[0][0][ip] + : 0.0; + + // *** upwinding *** + // Step 3.4: upwinding based on the sign of the phase potential gradient + // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way + + if( potDif >= 0 ) // the element is upstream + { + + // compute the phase flux and derivatives using the element mobility + phaseFlux = m_phaseMob[er][esr][ei][ip] * f; + dPhaseFlux_dP = m_phaseMob[er][esr][ei][ip] * dF_dP + m_dPhaseMob[er][esr][ei][ip][Deriv::dP] * f; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[jc] = + m_phaseMob[er][esr][ei][ip] * dF_dC[jc] + m_dPhaseMob[er][esr][ei][ip][Deriv::dC+jc] * f; + } + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = + m_phaseCompFrac[er][esr][ei][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = + m_dPhaseCompFrac[er][esr][ei][0][ip]; + + // compute component fluxes and derivatives using element composition + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + stack.compFlux[ic] += phaseFlux * ycp; + stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; + + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + dPhaseCompFracSub[ic], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp + phaseFlux * dProp_dC[jc]; + } + } + + } + else // the face is upstream + { + + // compute the phase flux and derivatives using the approximated face mobility + // we only have to take derivatives of the potential gradient in this case + phaseFlux = facePhaseMob * f; + dPhaseFlux_dP = facePhaseMob * dF_dP; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[jc] = facePhaseMob * dF_dC[jc]; + } + + // compute component fluxes and derivatives using the face composition + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = facePhaseCompFrac[0][0][ip][ic]; + stack.compFlux[ic] += phaseFlux * ycp; + stack.dCompFlux_dP[ic] += dPhaseFlux_dP * ycp; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dCompFlux_dC[ic][jc] += dPhaseFlux_dC[jc] * ycp; + } + } + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + compFluxKernelOp( ip, er, esr, ei, kf, f, + facePhaseMob, facePhaseEnthalpy[0][0], facePhaseCompFrac[0][0], + phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); + + } + + // *** end of upwinding + + // Step 4: populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localFlux[ic] = m_dt * stack.compFlux[ic]; + stack.localFluxJacobian[ic][0] = m_dt * stack.dCompFlux_dP[ic]; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localFluxJacobian[ic][jc+1] = m_dt * stack.dCompFlux_dC[ic][jc]; + } + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using namespace compositionalMultiphaseUtilities; + using Order = BoundaryStencil::Order; + + if( AbstractBase::m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) ) + { + // Apply equation/variable change transformation(s) + real64 work[numDof]{}; + shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localFluxJacobian, work ); + shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localFlux ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + if( m_ghostRank[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( AbstractBase::m_localMatrix.numRows(), localRow + numComp ); + + for( integer ic = 0; ic < numComp; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + ic], stack.localFlux[ic] ); + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + ic, + stack.dofColIndices, + stack.localFluxJacobian[ic], + numDof ); + } + + // call the lambda to assemble additional terms, such as thermal terms + assemblyKernelOp( localRow ); + } + } + +protected: + + /// Views on face pressure, temperature, and composition + arrayView1d< real64 const > const m_facePres; + arrayView1d< real64 const > const m_faceTemp; + arrayView2d< real64 const, compflow::USD_COMP > const m_faceCompFrac; + + /// View on the face gravity coefficient + arrayView1d< real64 const > const m_faceGravCoef; + + /// Reference to the fluid wrapper + FLUIDWRAPPER const m_fluidWrapper; + +}; + + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +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 string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the boundary stencil wrapper + * @param[in] fluidBase the multifluid constitutive model + * @param[in] dt time step size + * @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, + integer const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const & dofKey, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + BoundaryStencilWrapper const & stencilWrapper, + constitutive::MultiFluidBase & fluidBase, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutive::constitutiveComponentUpdatePassThru( fluidBase, numComps, [&]( auto & fluid, auto NC ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + // for now, we neglect capillary pressure in the kernel + BitFlags< KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + + using kernelType = DirichletFluxComputeKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, + dofNumberAccessor, compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/DissipationCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp similarity index 86% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/DissipationCompositionalMultiphaseFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp index 7a316a92355..1b4183c8c1a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/DissipationCompositionalMultiphaseFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp @@ -14,13 +14,14 @@ */ /** - * @file DissipationCompositionalMultiphaseFVMKernels.hpp + * @file DissipationFluxComputeKernel.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_DISSIPATIONCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_DISSIPATIONCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DISSIPATIONFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DISSIPATIONFLUXCOMPUTEKERNEL_HPP -#include "IsothermalCompositionalMultiphaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "constitutive/solid/porosity/PorosityBase.hpp" #include "constitutive/solid/porosity/PorosityFields.hpp" @@ -34,17 +35,17 @@ static constexpr integer newtonContinuationCutoffIteration = 5; static constexpr real64 initialDirectionalCoef = 100; static constexpr real64 multiplierDirectionalCoef = 1000; -/******************************** FaceBasedAssemblyKernel ********************************/ +/******************************** FluxComputeKernel ********************************/ /** - * @class FaceBasedAssemblyKernel + * @class FluxComputeKernel * @tparam NUM_COMP number of fluid components * @tparam NUM_DOF number of degrees of freedom * @tparam STENCILWRAPPER the type of the stencil wrapper * @brief Define the interface for the assembly kernel in charge of flux terms */ template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +class FluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > { public: @@ -57,7 +58,7 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using CompFlowAccessors = AbstractBase::CompFlowAccessors; using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; @@ -68,7 +69,7 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne using AbstractBase::m_gravCoef; using AbstractBase::m_dCompFrac_dCompDens; - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; using Base::numComp; using Base::numDof; using Base::numEqn; @@ -110,26 +111,26 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne * @param[in] kappamin minimum value for kappa coefficient in DBC * @param[in] contMultiplier continuation multiplier factor (should be < 1) */ - FaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - DissCompFlowAccessors const & dissCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - PorosityAccessors const & porosityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags, - real64 const omega, - integer const curNewton, - integer const continuation, - integer const miscible, - real64 const kappamin, - real64 const contMultiplier ) + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + DissCompFlowAccessors const & dissCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + PorosityAccessors const & porosityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags, + real64 const omega, + integer const curNewton, + integer const continuation, + integer const miscible, + real64 const kappamin, + real64 const contMultiplier ) : Base( numPhases, rankOffset, stencilWrapper, @@ -319,9 +320,9 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne }; /** - * @class FaceBasedAssemblyKernelFactory + * @class FluxComputeKernelFactory */ -class FaceBasedAssemblyKernelFactory +class FluxComputeKernelFactory { public: @@ -372,13 +373,13 @@ class FaceBasedAssemblyKernelFactory elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; if( hasCapPressure ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ); + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ); if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); - using KERNEL_TYPE = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using KERNEL_TYPE = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); typename KERNEL_TYPE::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); typename KERNEL_TYPE::CapPressureAccessors capPressureAccessors( elemManager, solverName ); @@ -399,4 +400,4 @@ class FaceBasedAssemblyKernelFactory } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_DISSIPATIONCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_DISSIPATIONFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp new file mode 100644 index 00000000000..9389da529de --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp @@ -0,0 +1,77 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluidUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUIDUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUIDUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** FluidUpdateKernel ********************************/ + +struct FluidUpdateKernel +{ + template< typename POLICY, typename FLUID_WRAPPER > + static void + launch( localIndex const size, + FLUID_WRAPPER const & fluidWrapper, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & temp, + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) + { + fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); + } + } ); + } + + template< typename POLICY, typename FLUID_WRAPPER > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + FLUID_WRAPPER const & fluidWrapper, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & temp, + arrayView2d< real64 const, compflow::USD_COMP > const & compFrac ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + localIndex const k = targetSet[a]; + for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) + { + fluidWrapper.update( k, q, pres[k], temp[k], compFrac[k] ); + } + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALCOMPOSITIONALMULTIPHASEBASEKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp new file mode 100644 index 00000000000..d28ecf41b41 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp @@ -0,0 +1,575 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp" + +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseUtilities.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/** + * @class FluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public FluxComputeKernelBase +{ +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 (all of them, except the volume balance equation) + static constexpr integer numEqn = NUM_DOF-1; + + /// Maximum number of elements at the face + static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; + + /// Maximum number of connections at the face + static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; + + /// Maximum number of points in the stencil + static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; + + /// Number of flux support points (hard-coded for TFPA) + static constexpr integer numFluxSupportPoints = 2; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @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 + */ + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : FluxComputeKernelBase( numPhases, + rankOffset, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), + m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), + m_phaseMob( compFlowAccessors.get( fields::flow::phaseMobility {} ) ), + m_dPhaseMob( compFlowAccessors.get( fields::flow::dPhaseMobility {} ) ), + m_phaseMassDens( multiFluidAccessors.get( fields::multifluid::phaseMassDensity {} ) ), + m_dPhaseMassDens( multiFluidAccessors.get( fields::multifluid::dPhaseMassDensity {} ) ), + m_phaseCapPressure( capPressureAccessors.get( fields::cappres::phaseCapPressure {} ) ), + m_dPhaseCapPressure_dPhaseVolFrac( capPressureAccessors.get( fields::cappres::dPhaseCapPressure_dPhaseVolFraction {} ) ), + m_stencilWrapper( stencilWrapper ), + m_seri( stencilWrapper.getElementRegionIndices() ), + m_sesri( stencilWrapper.getElementSubRegionIndices() ), + m_sei( stencilWrapper.getElementIndices() ) + { } + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + 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, localIndex numElems ) + : stencilSize( size ), + numConnectedElems( numElems ), + dofColIndices( size * numDof ), + localFlux( numElems * numEqn ), + localFluxJacobian( numElems * numEqn, size * numDof ) + {} + + // Stencil information + + /// Stencil size for a given connection + localIndex const stencilSize; + /// Number of elements connected at a given connection + localIndex const numConnectedElems; + + // Transmissibility and derivatives + + /// Transmissibility + real64 transmissibility[maxNumConns][numFluxSupportPoints]{}; + /// Derivatives of transmissibility with respect to pressure + real64 dTrans_dPres[maxNumConns][numFluxSupportPoints]{}; + + // 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 equations except volume balance) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; + }; + + + /** + * @brief Getter for the stencil size at this connection + * @param[in] iconn the connection index + * @return the size of the stencil at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex stencilSize( localIndex const iconn ) const { return m_sei[iconn].size(); } + + /** + * @brief Getter for the number of elements at this connection + * @param[in] iconn the connection index + * @return the number of elements at this connection + */ + GEOS_HOST_DEVICE + inline + localIndex numPointsInFlux( localIndex const iconn ) const { return m_stencilWrapper.numPointsInFlux( iconn ); } + + + /** + * @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 + { + // set degrees of freedom indices for this face + for( integer i = 0; i < stack.stencilSize; ++i ) + { + globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[i * numDof + jdof] = offset + 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] iconn the connection 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 iconn, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + + // first, compute the transmissibilities at this face + m_stencilWrapper.computeWeights( iconn, + m_permeability, + m_dPerm_dPres, + stack.transmissibility, + stack.dTrans_dPres ); + + + localIndex k[numFluxSupportPoints]; + localIndex connectionIndex = 0; + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + /// cell indices + localIndex const seri[numFluxSupportPoints] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[numFluxSupportPoints] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[numFluxSupportPoints] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + // clear working arrays + real64 compFlux[numComp]{}; + real64 dCompFlux_dP[numFluxSupportPoints][numComp]{}; + real64 dCompFlux_dC[numFluxSupportPoints][numComp][numComp]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + real64 const dTrans_dPres[numFluxSupportPoints] = { stack.dTrans_dPres[connectionIndex][0], + stack.dTrans_dPres[connectionIndex][1] }; + + //***** calculation of flux ***** + // loop over phases, compute and upwind phase flux and sum contributions to each component's flux + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + // create local work arrays + real64 potGrad = 0.0; + real64 phaseFlux = 0.0; + real64 dPhaseFlux_dP[numFluxSupportPoints]{}; + real64 dPhaseFlux_dC[numFluxSupportPoints][numComp]{}; + + localIndex k_up = -1; + + if( m_kernelFlags.isSet( KernelFlags::C1PPU ) ) + { + isothermalCompositionalMultiphaseFVMKernelUtilities::C1PPUPhaseFlux::compute< numComp, numFluxSupportPoints > + ( m_numPhases, + ip, + m_kernelFlags.isSet( KernelFlags::CapPressure ), + seri, sesri, sei, + trans, + dTrans_dPres, + m_pres, + m_gravCoef, + m_phaseMob, m_dPhaseMob, + m_phaseVolFrac, m_dPhaseVolFrac, + m_phaseCompFrac, m_dPhaseCompFrac, + m_dCompFrac_dCompDens, + m_phaseMassDens, m_dPhaseMassDens, + m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, + k_up, + potGrad, + phaseFlux, + dPhaseFlux_dP, + dPhaseFlux_dC, + compFlux, + dCompFlux_dP, + dCompFlux_dC ); + } + else if( m_kernelFlags.isSet( KernelFlags::IHU ) ) + { + isothermalCompositionalMultiphaseFVMKernelUtilities::IHUPhaseFlux::compute< numComp, numFluxSupportPoints > + ( m_numPhases, + ip, + m_kernelFlags.isSet( KernelFlags::CapPressure ), + seri, sesri, sei, + trans, + dTrans_dPres, + m_pres, + m_gravCoef, + m_phaseMob, m_dPhaseMob, + m_phaseVolFrac, m_dPhaseVolFrac, + m_phaseCompFrac, m_dPhaseCompFrac, + m_dCompFrac_dCompDens, + m_phaseMassDens, m_dPhaseMassDens, + m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, + k_up, + potGrad, + phaseFlux, + dPhaseFlux_dP, + dPhaseFlux_dC, + compFlux, + dCompFlux_dP, + dCompFlux_dC ); + } + else + { + isothermalCompositionalMultiphaseFVMKernelUtilities::PPUPhaseFlux::compute< numComp, numFluxSupportPoints > + ( m_numPhases, + ip, + m_kernelFlags.isSet( KernelFlags::CapPressure ), + seri, sesri, sei, + trans, + dTrans_dPres, + m_pres, + m_gravCoef, + m_phaseMob, m_dPhaseMob, + m_phaseVolFrac, m_dPhaseVolFrac, + m_phaseCompFrac, m_dPhaseCompFrac, + m_dCompFrac_dCompDens, + m_phaseMassDens, m_dPhaseMassDens, + m_phaseCapPressure, m_dPhaseCapPressure_dPhaseVolFrac, + k_up, + potGrad, + phaseFlux, + dPhaseFlux_dP, + dPhaseFlux_dC, + compFlux, + dCompFlux_dP, + dCompFlux_dC ); + } + + // call the lambda in the phase loop to allow the reuse of the phase fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + compFluxKernelOp( ip, k, seri, sesri, sei, connectionIndex, + k_up, seri[k_up], sesri[k_up], sei[k_up], potGrad, + phaseFlux, dPhaseFlux_dP, dPhaseFlux_dC ); + + } // loop over phases + + /// populate local flux vector and derivatives + for( integer ic = 0; ic < numComp; ++ic ) + { + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + stack.localFlux[eqIndex0] += m_dt * compFlux[ic]; + stack.localFlux[eqIndex1] -= m_dt * compFlux[ic]; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[eqIndex0][localDofIndexPres] += m_dt * dCompFlux_dP[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexPres] -= m_dt * dCompFlux_dP[ke][ic]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + localIndex const localDofIndexComp = localDofIndexPres + jc + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexComp] += m_dt * dCompFlux_dC[ke][ic][jc]; + stack.localFluxJacobian[eqIndex1][localDofIndexComp] -= m_dt * dCompFlux_dC[ke][ic][jc]; + } + } + } + connectionIndex++; + } // loop over k[1] + } // loop over k[0] + + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using namespace compositionalMultiphaseUtilities; + + if( m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) ) + { + // Apply equation/variable change transformation(s) + stackArray1d< real64, maxStencilSize * numDof > work( stack.stencilSize * numDof ); + shiftBlockRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numEqn, numDof * stack.stencilSize, stack.numConnectedElems, + stack.localFluxJacobian, work ); + shiftBlockElementsAheadByOneAndReplaceFirstElementWithSum( numComp, numEqn, stack.numConnectedElems, + stack.localFlux ); + } + + // add contribution to residual and jacobian into: + // - the component mass balance equations (i = 0 to i = numComp-1) + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + for( integer i = 0; i < stack.numConnectedElems; ++i ) + { + if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow + numComp ); + + for( integer ic = 0; ic < numComp; ++ic ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow + ic], + stack.localFlux[i * numEqn + ic] ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + ic, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn + ic].dataIfContiguous(), + stack.stencilSize * numDof ); + } + + // call the lambda to assemble additional terms, such as thermal terms + assemblyKernelOp( i, localRow ); + } + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numConnections the number of connections + * @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 numConnections, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + kernelComponent.numPointsInFlux( iconn ) ); + + kernelComponent.setup( iconn, stack ); + kernelComponent.computeFlux( iconn, stack ); + kernelComponent.complete( iconn, stack ); + } ); + } + +protected: + + /// Views on permeability + ElementViewConst< arrayView3d< real64 const > > const m_permeability; + ElementViewConst< arrayView3d< real64 const > > const m_dPerm_dPres; + + /// Views on phase mobilities + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseMob; + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseMob; + + /// Views on phase mass densities + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseMassDens; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseMassDens; + + /// Views on phase capillary pressure + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const m_phaseCapPressure; + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const m_dPhaseCapPressure_dPhaseVolFrac; + + // Stencil information + + /// Reference to the stencil wrapper + STENCILWRAPPER const m_stencilWrapper; + + /// Connection to element maps + typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; + +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @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 string to get the element degrees of freedom numbers + * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasCapPressure, + integer const useTotalMassEquation, + UpwindingParameters upwindingParams, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + 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() + 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< KernelFlags > kernelFlags; + if( hasCapPressure ) + kernelFlags.set( KernelFlags::CapPressure ); + if( useTotalMassEquation ) + kernelFlags.set( KernelFlags::TotalMassEquation ); + if( upwindingParams.upwindingScheme == UpwindingScheme::C1PPU && + isothermalCompositionalMultiphaseFVMKernelUtilities::epsC1PPU > 0 ) + kernelFlags.set( KernelFlags::C1PPU ); + else if( upwindingParams.upwindingScheme == UpwindingScheme::IHU ) + kernelFlags.set( KernelFlags::IHU ); + + + using kernelType = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, + compFlowAccessors, multiFluidAccessors, capPressureAccessors, permeabilityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp new file mode 100644 index 00000000000..f3f33c92d69 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp @@ -0,0 +1,65 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernelBase.cpp + */ + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp" + +#include "finiteVolume/CellElementStencilTPFA.hpp" +#include "finiteVolume/SurfaceElementStencil.hpp" +#include "finiteVolume/EmbeddedSurfaceToCellStencil.hpp" +#include "finiteVolume/FaceElementToCellStencil.hpp" +#include "mesh/utilities/MeshMapUtilities.hpp" + +namespace geos +{ +using namespace constitutive; + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** FluxComputeKernelBase ********************************/ + +FluxComputeKernelBase::FluxComputeKernelBase( integer const numPhases, + globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ) + : m_numPhases( numPhases ), + m_rankOffset( rankOffset ), + m_dt( dt ), + m_dofNumber( dofNumberAccessor.toNestedViewConst() ), + m_ghostRank( compFlowAccessors.get( fields::ghostRank {} ) ), + m_gravCoef( compFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), + m_pres( compFlowAccessors.get( fields::flow::pressure {} ) ), + m_phaseVolFrac( compFlowAccessors.get( fields::flow::phaseVolumeFraction {} ) ), + m_dPhaseVolFrac( compFlowAccessors.get( fields::flow::dPhaseVolumeFraction {} ) ), + m_dCompFrac_dCompDens( compFlowAccessors.get( fields::flow::dGlobalCompFraction_dGlobalCompDensity {} ) ), + m_phaseCompFrac( multiFluidAccessors.get( fields::multifluid::phaseCompFraction {} ) ), + m_dPhaseCompFrac( multiFluidAccessors.get( fields::multifluid::dPhaseCompFraction {} ) ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ), + m_kernelFlags( kernelFlags ) +{} + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp new file mode 100644 index 00000000000..f36124d6ed6 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp @@ -0,0 +1,181 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNELBASE_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/capillaryPressure/CapillaryPressureFields.hpp" +#include "constitutive/capillaryPressure/CapillaryPressureBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/permeability/PermeabilityBase.hpp" +#include "constitutive/permeability/PermeabilityFields.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +enum class KernelFlags +{ + /// Flag to specify whether capillary pressure is used or not + CapPressure = 1 << 0, // 1 + /// Flag indicating whether total mass equation is formed or not + TotalMassEquation = 1 << 1, // 2 + /// Flag indicating whether C1-PPU is used or not + C1PPU = 1 << 2, // 4 + /// Flag indicating whether IHU is used or not + IHU = 1 << 3 // 8 + /// Add more flags like that if needed: + // Flag5 = 1 << 4, // 16 + // Flag6 = 1 << 5, // 32 + // Flag7 = 1 << 6, // 64 + // Flag8 = 1 << 7 //128 +}; + +/******************************** FluxComputeKernelBase ********************************/ + +/** + * @brief Base class for FluxComputeKernel that holds all data not dependent + * on template parameters (like stencil type and number of components/dofs). + */ +class FluxComputeKernelBase +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; + + using CompFlowAccessors = + StencilAccessors< fields::ghostRank, + fields::flow::gravityCoefficient, + fields::flow::pressure, + fields::flow::dGlobalCompFraction_dGlobalCompDensity, + fields::flow::phaseVolumeFraction, + fields::flow::dPhaseVolumeFraction, + fields::flow::phaseMobility, + fields::flow::dPhaseMobility >; + using MultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseDensity, + fields::multifluid::dPhaseDensity, + fields::multifluid::phaseMassDensity, + fields::multifluid::dPhaseMassDensity, + fields::multifluid::phaseCompFraction, + fields::multifluid::dPhaseCompFraction >; + + using CapPressureAccessors = + StencilMaterialAccessors< constitutive::CapillaryPressureBase, + fields::cappres::phaseCapPressure, + fields::cappres::dPhaseCapPressure_dPhaseVolFraction >; + + using PermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure >; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofNumberAccessor accessor for the dof numbers + * @param[in] compFlowAccessors accessor for wrappers registered by the solver + * @param[in] multiFluidAccessors accessor for wrappers registered by the multifluid model + * @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 all together + */ + FluxComputeKernelBase( integer const numPhases, + globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< KernelFlags > kernelFlags ); + +protected: + + /// Number of fluid phases + integer const m_numPhases; + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// Time step size + real64 const m_dt; + + /// Views on dof numbers + ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; + + /// Views on ghost rank numbers and gravity coefficients + ElementViewConst< arrayView1d< integer const > > const m_ghostRank; + ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; + + // Primary and secondary variables + + /// Views on pressure + ElementViewConst< arrayView1d< real64 const > > const m_pres; + + /// Views on phase volume fractions + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseVolFrac; + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const m_dPhaseVolFrac; + + /// Views on derivatives of comp fractions + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dCompFrac_dCompDens; + + /// Views on phase component fractions + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_phaseCompFrac; + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const m_dPhaseCompFrac; + + // Residual and jacobian + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + + BitFlags< KernelFlags > const m_kernelFlags; +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_FLUXCOMPUTEKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp new file mode 100644 index 00000000000..e8d53a625ba --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp @@ -0,0 +1,144 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file GlobalComponentFractionKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_GLOBALCOMPONENTFRACTIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_GLOBALCOMPONENTFRACTIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** GlobalComponentFractionKernel ********************************/ + +/** + * @class GlobalComponentFractionKernel + * @tparam NUM_COMP number of fluid components + * @brief Define the interface for the update kernel in charge of computing the phase volume fractions + */ +template< integer NUM_COMP > +class GlobalComponentFractionKernel : public PropertyKernelBase< NUM_COMP > +{ +public: + + using Base = PropertyKernelBase< NUM_COMP >; + using Base::numComp; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + GlobalComponentFractionKernel( ObjectManagerBase & subRegion ) + : Base(), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_compFrac( subRegion.getField< fields::flow::globalCompFraction >() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ) + {} + + /** + * @brief Compute the phase volume fractions 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] phaseVolFractionKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void compute( localIndex const ei, + FUNC && compFractionKernelOp = NoOpFunc{} ) const + { + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; + arraySlice1d< real64, compflow::USD_COMP - 1 > const compFrac = m_compFrac[ei]; + arraySlice2d< real64, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + + real64 totalDensity = 0.0; + + for( integer ic = 0; ic < numComp; ++ic ) + { + totalDensity += compDens[ic]; + } + + real64 const totalDensityInv = 1.0 / totalDensity; + + for( integer ic = 0; ic < numComp; ++ic ) + { + compFrac[ic] = compDens[ic] * totalDensityInv; + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFrac_dCompDens[ic][jc] = -compFrac[ic] * totalDensityInv; + } + dCompFrac_dCompDens[ic][ic] += totalDensityInv; + } + + compFractionKernelOp( compFrac, dCompFrac_dCompDens ); + } + +protected: + + // inputs + + // Views on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + + // outputs + + // Views on component fraction + arrayView2d< real64, compflow::USD_COMP > m_compFrac; + arrayView3d< real64, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; + +}; + +/** + * @class GlobalComponentFractionKernelFactory + */ +class GlobalComponentFractionKernelFactory +{ +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] subRegion the element subregion + * @param[in] fluid the fluid model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + ObjectManagerBase & subRegion ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + GlobalComponentFractionKernel< NUM_COMP > kernel( subRegion ); + GlobalComponentFractionKernel< NUM_COMP >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_GLOBALCOMPONENTFRACTIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp new file mode 100644 index 00000000000..65b6bde6360 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp @@ -0,0 +1,356 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydrostaticPressureKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "functions/TableFunction.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** HydrostaticPressureKernel ********************************/ + +struct HydrostaticPressureKernel +{ + + // TODO: this type of constants should be centralized somewhere or provided by fluid model + static real64 constexpr MIN_FOR_PHASE_PRESENCE = 1e-12; + + enum class ReturnType : integer + { + FAILED_TO_CONVERGE = 0, + DETECTED_MULTIPHASE_FLOW = 1, + SUCCESS = 2 + }; + + template< typename FLUID_WRAPPER > + static ReturnType + computeHydrostaticPressure( integer const numComps, + integer const numPhases, + integer const ipInit, + integer const maxNumEquilIterations, + real64 const & equilTolerance, + real64 const (&gravVector)[ 3 ], + FLUID_WRAPPER fluidWrapper, + arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, + TableFunction::KernelWrapper tempTableWrapper, + real64 const & refElevation, + real64 const & refPres, + arraySlice1d< real64 const > const & refPhaseMassDens, + real64 const & newElevation, + real64 & newPres, + arraySlice1d< real64 > const & newPhaseMassDens ) + { + // fluid properties at this elevation + StackArray< real64, 2, constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, compflow::LAYOUT_COMP > compFrac( 1, numComps ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseFrac( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseDens( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseMassDens( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseVisc( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseEnthalpy( 1, 1, numPhases ); + StackArray< real64, 3, constitutive::MultiFluidBase::MAX_NUM_PHASES, constitutive::multifluid::LAYOUT_PHASE > phaseInternalEnergy( 1, 1, numPhases ); + StackArray< real64, 4, constitutive::MultiFluidBase::MAX_NUM_PHASES *constitutive::MultiFluidBase::MAX_NUM_COMPONENTS, + constitutive::multifluid::LAYOUT_PHASE_COMP > phaseCompFrac( 1, 1, numPhases, numComps ); + real64 totalDens = 0.0; + + bool isSinglePhaseFlow = true; + + // Step 1: compute the hydrostatic pressure at the current elevation + + real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); + real64 const temp = tempTableWrapper.compute( &newElevation ); + for( integer ic = 0; ic < numComps; ++ic ) + { + compFrac[0][ic] = compFracTableWrappers[ic].compute( &newElevation ); + } + + // Step 2: guess the pressure with the refPhaseMassDensity + + real64 pres0 = refPres - refPhaseMassDens[ipInit] * gravCoef; + real64 pres1 = 0.0; + + // Step 3: compute the mass density at this elevation using the guess, and update pressure + + constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, + pres0, + temp, + compFrac[0], + phaseFrac[0][0], + phaseDens[0][0], + phaseMassDens[0][0], + phaseVisc[0][0], + phaseEnthalpy[0][0], + phaseInternalEnergy[0][0], + phaseCompFrac[0][0], + totalDens ); + pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; + + // Step 4: fixed-point iteration until convergence + + bool equilHasConverged = false; + for( integer eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) + { + + // check convergence + equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); + pres0 = pres1; + + // if converged, check number of phases and move on + if( equilHasConverged ) + { + // make sure that the fluid is single-phase, other we have to issue a warning (for now) + // if only one phase is mobile, we are in good shape (unfortunately it is hard to access relperm from here) + localIndex numberOfPhases = 0; + for( integer ip = 0; ip < numPhases; ++ip ) + { + if( phaseFrac[0][0][ip] > MIN_FOR_PHASE_PRESENCE ) + { + numberOfPhases++; + } + } + if( numberOfPhases > 1 ) + { + isSinglePhaseFlow = false; + } + + break; + } + + // compute the mass density at this elevation using the previous pressure, and compute the new pressure + constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, + pres0, + temp, + compFrac[0], + phaseFrac[0][0], + phaseDens[0][0], + phaseMassDens[0][0], + phaseVisc[0][0], + phaseEnthalpy[0][0], + phaseInternalEnergy[0][0], + phaseCompFrac[0][0], + totalDens ); + pres1 = refPres - 0.5 * ( refPhaseMassDens[ipInit] + phaseMassDens[0][0][ipInit] ) * gravCoef; + } + + // Step 5: save the hydrostatic pressure and the corresponding density + + newPres = pres1; + for( integer ip = 0; ip < numPhases; ++ip ) + { + newPhaseMassDens[ip] = phaseMassDens[0][0][ip]; + } + + if( !equilHasConverged ) + { + return ReturnType::FAILED_TO_CONVERGE; + } + else if( !isSinglePhaseFlow ) + { + return ReturnType::DETECTED_MULTIPHASE_FLOW; + } + else + { + return ReturnType::SUCCESS; + } + } + + template< typename FLUID_WRAPPER > + static ReturnType + launch( localIndex const size, + integer const numComps, + integer const numPhases, + integer const ipInit, + integer const maxNumEquilIterations, + real64 const equilTolerance, + real64 const (&gravVector)[ 3 ], + real64 const & minElevation, + real64 const & elevationIncrement, + real64 const & datumElevation, + real64 const & datumPres, + FLUID_WRAPPER fluidWrapper, + arrayView1d< TableFunction::KernelWrapper const > compFracTableWrappers, + TableFunction::KernelWrapper tempTableWrapper, + arrayView1d< arrayView1d< real64 > const > elevationValues, + arrayView1d< real64 > pressureValues ) + { + + ReturnType returnVal = ReturnType::SUCCESS; + + // Step 1: compute the phase mass densities at datum + + // datum fluid properties + array2d< real64, compflow::LAYOUT_COMP > datumCompFrac( 1, numComps ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseFrac( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseDens( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseMassDens( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseVisc( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseEnthalpy( 1, 1, numPhases ); + array3d< real64, constitutive::multifluid::LAYOUT_PHASE > datumPhaseInternalEnergy( 1, 1, numPhases ); + array4d< real64, constitutive::multifluid::LAYOUT_PHASE_COMP > datumPhaseCompFrac( 1, 1, numPhases, numComps ); + real64 datumTotalDens = 0.0; + + real64 const datumTemp = tempTableWrapper.compute( &datumElevation ); + for( integer ic = 0; ic < numComps; ++ic ) + { + datumCompFrac[0][ic] = compFracTableWrappers[ic].compute( &datumElevation ); + } + constitutive::MultiFluidBase::KernelWrapper::computeValues( fluidWrapper, + datumPres, + datumTemp, + datumCompFrac[0], + datumPhaseFrac[0][0], + datumPhaseDens[0][0], + datumPhaseMassDens[0][0], + datumPhaseVisc[0][0], + datumPhaseEnthalpy[0][0], + datumPhaseInternalEnergy[0][0], + datumPhaseCompFrac[0][0], + datumTotalDens ); + + // Step 2: find the closest elevation to datumElevation + + forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) + { + real64 const elevation = minElevation + i * elevationIncrement; + elevationValues[0][i] = elevation; + } ); + integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), + elevationValues[0].size(), + datumElevation ); + + // Step 3: compute the mass density and pressure at the reference elevation + + array2d< real64 > phaseMassDens( pressureValues.size(), numPhases ); + // temporary array without permutation to compile on Lassen + array1d< real64 > datumPhaseMassDensTmp( numPhases ); + for( integer ip = 0; ip < numPhases; ++ip ) + { + datumPhaseMassDensTmp[ip] = datumPhaseMassDens[0][0][ip]; + } + + ReturnType const refReturnVal = + computeHydrostaticPressure( numComps, + numPhases, + ipInit, + maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + compFracTableWrappers, + tempTableWrapper, + datumElevation, + datumPres, + datumPhaseMassDensTmp, + elevationValues[0][iRef], + pressureValues[iRef], + phaseMassDens[iRef] ); + if( refReturnVal == ReturnType::FAILED_TO_CONVERGE ) + { + return ReturnType::FAILED_TO_CONVERGE; + } + else if( refReturnVal == ReturnType::DETECTED_MULTIPHASE_FLOW ) + { + returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; + } + + // Step 4: for each elevation above the reference elevation, compute the pressure + + localIndex const numEntriesAboveRef = size - iRef - 1; + forAll< serialPolicy >( numEntriesAboveRef, [=, &returnVal] ( localIndex const i ) + { + ReturnType const returnValAboveRef = + computeHydrostaticPressure( numComps, + numPhases, + ipInit, + maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + compFracTableWrappers, + tempTableWrapper, + elevationValues[0][iRef+i], + pressureValues[iRef+i], + phaseMassDens[iRef+i], + elevationValues[0][iRef+i+1], + pressureValues[iRef+i+1], + phaseMassDens[iRef+i+1] ); + if( returnValAboveRef == ReturnType::FAILED_TO_CONVERGE ) + { + returnVal = ReturnType::FAILED_TO_CONVERGE; + } + else if( ( returnValAboveRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && + ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) + { + returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; + } + + } ); + + // Step 5: for each elevation below the reference elevation, compute the pressure + + localIndex const numEntriesBelowRef = iRef; + forAll< serialPolicy >( numEntriesBelowRef, [=, &returnVal] ( localIndex const i ) + { + ReturnType const returnValBelowRef = + computeHydrostaticPressure( numComps, + numPhases, + ipInit, + maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + compFracTableWrappers, + tempTableWrapper, + elevationValues[0][iRef-i], + pressureValues[iRef-i], + phaseMassDens[iRef-i], + elevationValues[0][iRef-i-1], + pressureValues[iRef-i-1], + phaseMassDens[iRef-i-1] ); + if( returnValBelowRef == ReturnType::FAILED_TO_CONVERGE ) + { + returnVal = ReturnType::FAILED_TO_CONVERGE; + } + else if( ( returnValBelowRef == ReturnType::DETECTED_MULTIPHASE_FLOW ) && + ( returnVal != ReturnType::FAILED_TO_CONVERGE ) ) + { + returnVal = ReturnType::DETECTED_MULTIPHASE_FLOW; + } + + } ); + + return returnVal; + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_HYDROSTATICPRESSUREKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp similarity index 82% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp index 323f3e362d0..ec9b3c55783 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp @@ -14,11 +14,11 @@ */ /** - * @file IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp + * @file IHUPhaseFlux.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELUTILITIES_HPP_ -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELUTILITIES_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_IHUPHASEFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_IHUPHASEFLUX_HPP #include "common/DataLayouts.hpp" #include "common/DataTypes.hpp" @@ -33,559 +33,11 @@ namespace geos namespace isothermalCompositionalMultiphaseFVMKernelUtilities { -// TODO make input parameter -static constexpr real64 epsC1PPU = 5000; - template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; using Deriv = constitutive::multifluid::DerivativeOffset; -struct PotGrad -{ - template< integer numComp, integer numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute ( integer const numPhase, - integer const ip, - integer const hasCapPressure, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - real64 const ( &trans )[numFluxSupportPoints], - real64 const ( &dTrans_dPres )[numFluxSupportPoints], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, - ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, - ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, - real64 & potGrad, - real64 ( & dPresGrad_dP )[numFluxSupportPoints], - real64 ( & dPresGrad_dC )[numFluxSupportPoints][numComp], - real64 ( & dGravHead_dP )[numFluxSupportPoints], - real64 ( & dGravHead_dC )[numFluxSupportPoints][numComp] ) - { - // assign derivatives arrays to zero - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - dPresGrad_dP[i] = 0.0; - dGravHead_dP[i] = 0.0; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPresGrad_dC[i][jc] = 0.0; - dGravHead_dC[i][jc] = 0.0; - } - } - - // create local work arrays - real64 densMean = 0.0; - real64 dDensMean_dP[numFluxSupportPoints]{}; - real64 dDensMean_dC[numFluxSupportPoints][numComp]{}; - - real64 presGrad = 0.0; - real64 gravHead = 0.0; - real64 dCapPressure_dC[numComp]{}; - - real64 dProp_dC[numComp]{}; - - // calculate quantities on primary connected cells - integer denom = 0; - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - bool const phaseExists = (phaseVolFrac[er][esr][ei][ip] > 0); - if( !phaseExists ) - { - continue; - } - - // density - real64 const density = phaseMassDens[er][esr][ei][0][ip]; - real64 const dDens_dP = dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; - - applyChainRule( numComp, - dCompFrac_dCompDens[er][esr][ei], - dPhaseMassDens[er][esr][ei][0][ip], - dProp_dC, - Deriv::dC ); - - // average density and derivatives - densMean += density; - dDensMean_dP[i] = dDens_dP; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDensMean_dC[i][jc] = dProp_dC[jc]; - } - denom++; - } - if( denom > 1 ) - { - densMean /= denom; - for( integer i = 0; i < numFluxSupportPoints; ++i ) - { - dDensMean_dP[i] /= denom; - for( integer jc = 0; jc < numComp; ++jc ) - { - dDensMean_dC[i][jc] /= denom; - } - } - } - - /// compute the TPFA potential difference - for( integer i = 0; i < numFluxSupportPoints; i++ ) - { - localIndex const er = seri[i]; - localIndex const esr = sesri[i]; - localIndex const ei = sei[i]; - - // capillary pressure - real64 capPressure = 0.0; - real64 dCapPressure_dP = 0.0; - - for( integer ic = 0; ic < numComp; ++ic ) - { - dCapPressure_dC[ic] = 0.0; - } - - if( hasCapPressure ) - { - capPressure = phaseCapPressure[er][esr][ei][0][ip]; - - for( integer jp = 0; jp < numPhase; ++jp ) - { - real64 const dCapPressure_dS = dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; - dCapPressure_dP += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; - - for( integer jc = 0; jc < numComp; ++jc ) - { - dCapPressure_dC[jc] += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; - } - } - } - - presGrad += trans[i] * (pres[er][esr][ei] - capPressure); - dPresGrad_dP[i] += trans[i] * (1 - dCapPressure_dP) - + dTrans_dPres[i] * (pres[er][esr][ei] - capPressure); - for( integer jc = 0; jc < numComp; ++jc ) - { - dPresGrad_dC[i][jc] += -trans[i] * dCapPressure_dC[jc]; - } - - real64 const gravD = trans[i] * gravCoef[er][esr][ei]; - real64 const dGravD_dP = dTrans_dPres[i] * gravCoef[er][esr][ei]; - - // the density used in the potential difference is always a mass density - // unlike the density used in the phase mobility, which is a mass density - // if useMass == 1 and a molar density otherwise - gravHead += densMean * gravD; - - // need to add contributions from both cells the mean density depends on - for( integer j = 0; j < numFluxSupportPoints; ++j ) - { - dGravHead_dP[j] += dDensMean_dP[j] * gravD + dGravD_dP * densMean; - for( integer jc = 0; jc < numComp; ++jc ) - { - dGravHead_dC[j][jc] += dDensMean_dC[j][jc] * gravD; - } - } - } - - // compute phase potential gradient - potGrad = presGrad - gravHead; - - } - -}; - -struct PhaseComponentFlux -{ - /** - * @brief Compute the component flux for a given phase - * @tparam numComp number of components - * @tparam numFluxSupportPoints number of flux support points - * @param ip phase index - * @param k_up uptream index for this phase - * @param seri arraySlice of the stencil-implied element region index - * @param sesri arraySlice of the stencil-implied element subregion index - * @param sei arraySlice of the stencil-implied element index - * @param phaseCompFrac phase component fraction - * @param dPhaseCompFrac derivative of phase component fraction wrt pressure, temperature, component fraction - * @param dCompFrac_dCompDens derivative of component fraction wrt component density - * @param phaseFlux phase flux - * @param dPhaseFlux_dP derivative of phase flux wrt pressure - * @param dPhaseFlux_dC derivative of phase flux wrt comp density - * @param compFlux component flux - * @param dCompFlux_dP derivative of phase flux wrt pressure - * @param dCompFlux_dC derivative of phase flux wrt comp density - */ - template< localIndex numComp, localIndex numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute( localIndex const ip, - localIndex const k_up, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - real64 const & phaseFlux, - real64 const ( &dPhaseFlux_dP )[numFluxSupportPoints], - real64 const ( &dPhaseFlux_dC )[numFluxSupportPoints][numComp], - real64 ( & compFlux )[numComp], - real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], - real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) - { - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - real64 dProp_dC[numComp]{}; - - // slice some constitutive arrays to avoid too much indexing in component loop - arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = - phaseCompFrac[er_up][esr_up][ei_up][0][ip]; - arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = - dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; - - // compute component fluxes and derivatives using upstream cell composition - for( integer ic = 0; ic < numComp; ++ic ) - { - real64 const ycp = phaseCompFracSub[ic]; - compFlux[ic] += phaseFlux * ycp; - - // derivatives stemming from phase flux - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dCompFlux_dP[ke][ic] += dPhaseFlux_dP[ke] * ycp; - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFlux_dC[ke][ic][jc] += dPhaseFlux_dC[ke][jc] * ycp; - } - } - - // additional derivatives stemming from upstream cell phase composition - dCompFlux_dP[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; - - // convert derivatives of comp fraction w.r.t. comp fractions to derivatives w.r.t. comp densities - applyChainRule( numComp, - dCompFrac_dCompDens[er_up][esr_up][ei_up], - dPhaseCompFracSub[ic], - dProp_dC, - Deriv::dC ); - for( integer jc = 0; jc < numComp; ++jc ) - { - dCompFlux_dC[k_up][ic][jc] += phaseFlux * dProp_dC[jc]; - } - } - - - - } - -}; - -struct PPUPhaseFlux -{ - /** - * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head - * @tparam numComp number of components - * @tparam numFluxSupportPoints number of flux support points - * @param numPhase number of phases - * @param ip phase index - * @param hasCapPressure flag indicating if there is capillary pressure - * @param seri arraySlice of the stencil-implied element region index - * @param sesri arraySlice of the stencil-implied element subregion index - * @param sei arraySlice of the stencil-implied element index - * @param trans transmissibility at the connection - * @param dTrans_dPres derivative of transmissibility wrt pressure - * @param pres pressure - * @param gravCoef gravitational coefficient - * @param phaseMob phase mobility - * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density - * @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 phaseCapPressure phase capillary pressure - * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction - * @param k_up uptream index for this phase - * @param potGrad potential gradient for this phase - * @param phaseFlux phase flux - * @param dPhaseFlux_dP derivative of phase flux wrt pressure - * @param dPhaseFlux_dC derivative of phase flux wrt comp density - */ - template< integer numComp, integer numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute( integer const numPhase, - integer const ip, - integer const hasCapPressure, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - real64 const ( &trans )[2], - real64 const ( &dTrans_dPres )[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, - ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, - ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, - localIndex & k_up, - real64 & potGrad, - real64 ( &phaseFlux ), - real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], - real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp], - real64 ( & compFlux )[numComp], - real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], - real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) - { - real64 dPresGrad_dP[numFluxSupportPoints]{}; - real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; - real64 dGravHead_dP[numFluxSupportPoints]{}; - real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; - PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, seri, sesri, sei, trans, dTrans_dPres, pres, - gravCoef, phaseVolFrac, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, - phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, - dPresGrad_dC, dGravHead_dP, dGravHead_dC ); - - // *** upwinding *** - - // choose upstream cell - k_up = (potGrad >= 0) ? 0 : 1; - - localIndex const er_up = seri[k_up]; - localIndex const esr_up = sesri[k_up]; - localIndex const ei_up = sei[k_up]; - - real64 const mobility = phaseMob[er_up][esr_up][ei_up][ip]; - - // pressure gradient depends on all points in the stencil - for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) - { - dPhaseFlux_dP[ke] += dPresGrad_dP[ke] - dGravHead_dP[ke]; - dPhaseFlux_dP[ke] *= mobility; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[ke][jc] += dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; - dPhaseFlux_dC[ke][jc] *= mobility; - } - } - // compute phase flux using upwind mobility. - phaseFlux = mobility * potGrad; - - real64 const dMob_dP = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dP]; - arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > dPhaseMobSub = - dPhaseMob[er_up][esr_up][ei_up][ip]; - - // add contribution from upstream cell mobility derivatives - dPhaseFlux_dP[k_up] += dMob_dP * potGrad; - for( integer jc = 0; jc < numComp; ++jc ) - { - dPhaseFlux_dC[k_up][jc] += dPhaseMobSub[Deriv::dC+jc] * potGrad; - } - - //distribute on phaseComponentFlux here - PhaseComponentFlux::compute( ip, k_up, seri, sesri, sei, phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, phaseFlux - , dPhaseFlux_dP, dPhaseFlux_dC, compFlux, dCompFlux_dP, dCompFlux_dC ); - - } -}; - -struct C1PPUPhaseFlux -{ - /** - * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head - * @tparam numComp number of components - * @tparam numFluxSupportPoints number of flux support points - * @param numPhase number of phases - * @param ip phase index - * @param hasCapPressure flag indicating if there is capillary pressure - * @param seri arraySlice of the stencil-implied element region index - * @param sesri arraySlice of the stencil-implied element subregion index - * @param sei arraySlice of the stencil-implied element index - * @param trans transmissibility at the connection - * @param dTrans_dPres derivative of transmissibility wrt pressure - * @param pres pressure - * @param gravCoef gravitational coefficient - * @param phaseMob phase mobility - * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density - * @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 phaseCapPressure phase capillary pressure - * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction - * @param k_up uptream index for this phase - * @param potGrad potential gradient for this phase - * @param phaseFlux phase flux - * @param dPhaseFlux_dP derivative of phase flux wrt pressure - * @param dPhaseFlux_dC derivative of phase flux wrt comp density - */ - template< integer numComp, integer numFluxSupportPoints > - GEOS_HOST_DEVICE - static void - compute( integer const numPhase, - integer const ip, - integer const hasCapPressure, - localIndex const ( &seri )[numFluxSupportPoints], - localIndex const ( &sesri )[numFluxSupportPoints], - localIndex const ( &sei )[numFluxSupportPoints], - real64 const ( &trans )[2], - real64 const ( &dTrans_dPres )[2], - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, - ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, - ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, - ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, - ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, - ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, - ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, - ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, - localIndex & k_up, - real64 & potGrad, - real64 ( &phaseFlux ), - real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], - real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp], - real64 ( & compFlux )[numComp], - real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], - real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) - { - real64 dPresGrad_dP[numFluxSupportPoints]{}; - real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; - real64 dGravHead_dP[numFluxSupportPoints]{}; - real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; - PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, seri, sesri, sei, trans, dTrans_dPres, pres, - gravCoef, phaseVolFrac, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, - phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, - dPresGrad_dC, dGravHead_dP, dGravHead_dC ); - - // gravity head - real64 gravHead = 0.0; - 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 = Ttrans * ( 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]; - } - } - - potGrad = potGrad * Ttrans; - - // choose upstream cell for composition upwinding - k_up = (phaseFlux >= 0) ? 0 : 1; - - //distribute on phaseComponentFlux here - PhaseComponentFlux::compute( ip, k_up, seri, sesri, sei, phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, phaseFlux - , dPhaseFlux_dP, dPhaseFlux_dC, compFlux, dCompFlux_dP, dCompFlux_dC ); - } -}; - - - /************************* HELPERS ******************/ namespace UpwindHelpers { @@ -1040,7 +492,6 @@ computeFractionalFlowGravity( localIndex const numPhase, } } - template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > GEOS_HOST_DEVICE static void @@ -1091,7 +542,6 @@ computeFractionalFlowCapillary( localIndex const numPhase, } } - localIndex k_up; real64 mob{}; real64 dMob_dP{}; @@ -1121,7 +571,6 @@ computeFractionalFlowCapillary( localIndex const numPhase, dMob_dP, dMob_dC ); - k_up_main = k_up; mainMob = mob; dMMob_dP = dMob_dP; @@ -1375,15 +824,11 @@ struct computePotentialCapillary dPot_dComp[i][jc] += transmissibility[i] * dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dC + jc]; } - } - } - } }; - /// Form potential-related parts of fluxes template< localIndex numComp, localIndex numFluxSupportPoints, class UPWIND > @@ -1765,10 +1210,8 @@ static void computePotentialFluxesCapillary( localIndex const numPhase, } } } - } - }//end of struct UpwindHelpers /************************* UPWIND ******************/ @@ -2320,8 +1763,6 @@ struct IHUPhaseFlux dPhaseFlux_dC[ke][jc] = 0.; } } - - } //fractional flow loop with IHU @@ -2536,11 +1977,9 @@ struct IHUPhaseFlux }; - - } // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities } // namespace geos -#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_ISOTHERMALCOMPOSITIONALMULTIPHASEFVMKERNELUTILITIES_HPP_ +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_IHUPHASEFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp new file mode 100644 index 00000000000..0e7b2b84dc3 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp @@ -0,0 +1,159 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file KernelLaunchSelector.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_KERNELLAUNCHSELECTOR_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_KERNELLAUNCHSELECTOR_HPP + +#include "physicsSolvers/KernelLaunchSelectors.hpp" +#include "codingUtilities/Utilities.hpp" +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** Kernel launch machinery ********************************/ + +namespace internal +{ + +template< typename T, typename LAMBDA > +void kernelLaunchSelectorCompSwitch( T value, LAMBDA && lambda ) +{ + static_assert( std::is_integral< T >::value, "kernelLaunchSelectorCompSwitch: type should be integral" ); + + switch( value ) + { + case 1: + { lambda( std::integral_constant< T, 1 >() ); return; } + case 2: + { lambda( std::integral_constant< T, 2 >() ); return; } + case 3: + { lambda( std::integral_constant< T, 3 >() ); return; } + case 4: + { lambda( std::integral_constant< T, 4 >() ); return; } + case 5: + { lambda( std::integral_constant< T, 5 >() ); return; } + default: + { GEOS_ERROR( "Unsupported number of components: " << value ); } + } +} + +} // namespace internal + +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelectorCompTherm( integer const numComp, bool const isThermal, ARGS && ... args ) +{ + geos::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 ) +{ + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC() >( std::forward< ARGS >( args )... ); + } ); +} + +template< typename KERNELWRAPPER, typename ... ARGS > +void KernelLaunchSelector2( integer const numComp, integer const numPhase, 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( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 2 >( std::forward< ARGS >( args ) ... ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + KERNELWRAPPER::template launch< NC(), 3 >( std::forward< ARGS >( args ) ... ); + } ); + } + else + { + GEOS_ERROR( "Unsupported number of phases: " << numPhase ); + } +} + +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 + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_KERNELLAUNCHSELECTOR_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp new file mode 100644 index 00000000000..c8ac5256d98 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp @@ -0,0 +1,162 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PPUPhaseFlux.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PPUPHASEFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PPUPHASEFLUX_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct PPUPhaseFlux +{ + /** + * @brief Form the PhasePotentialUpwind from pressure gradient and gravitational head + * @tparam numComp number of components + * @tparam numFluxSupportPoints number of flux support points + * @param numPhase number of phases + * @param ip phase index + * @param hasCapPressure flag indicating if there is capillary pressure + * @param seri arraySlice of the stencil-implied element region index + * @param sesri arraySlice of the stencil-implied element subregion index + * @param sei arraySlice of the stencil-implied element index + * @param trans transmissibility at the connection + * @param dTrans_dPres derivative of transmissibility wrt pressure + * @param pres pressure + * @param gravCoef gravitational coefficient + * @param phaseMob phase mobility + * @param dPhaseMob derivative of phase mobility wrt pressure, temperature, comp density + * @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 phaseCapPressure phase capillary pressure + * @param dPhaseCapPressure_dPhaseVolFrac derivative of phase capillary pressure wrt phase volume fraction + * @param k_up uptream index for this phase + * @param potGrad potential gradient for this phase + * @param phaseFlux phase flux + * @param dPhaseFlux_dP derivative of phase flux wrt pressure + * @param dPhaseFlux_dC derivative of phase flux wrt comp density + */ + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute( integer const numPhase, + integer const ip, + integer const hasCapPressure, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + real64 const ( &trans )[2], + real64 const ( &dTrans_dPres )[2], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseMob, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseMob, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + localIndex & k_up, + real64 & potGrad, + real64 ( &phaseFlux ), + real64 ( & dPhaseFlux_dP )[numFluxSupportPoints], + real64 ( & dPhaseFlux_dC )[numFluxSupportPoints][numComp], + real64 ( & compFlux )[numComp], + real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], + real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) + { + real64 dPresGrad_dP[numFluxSupportPoints]{}; + real64 dPresGrad_dC[numFluxSupportPoints][numComp]{}; + real64 dGravHead_dP[numFluxSupportPoints]{}; + real64 dGravHead_dC[numFluxSupportPoints][numComp]{}; + PotGrad::compute< numComp, numFluxSupportPoints >( numPhase, ip, hasCapPressure, seri, sesri, sei, trans, dTrans_dPres, pres, + gravCoef, phaseVolFrac, dPhaseVolFrac, dCompFrac_dCompDens, phaseMassDens, dPhaseMassDens, + phaseCapPressure, dPhaseCapPressure_dPhaseVolFrac, potGrad, dPresGrad_dP, + dPresGrad_dC, dGravHead_dP, dGravHead_dC ); + + // *** upwinding *** + + // choose upstream cell + k_up = (potGrad >= 0) ? 0 : 1; + + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + real64 const mobility = phaseMob[er_up][esr_up][ei_up][ip]; + + // pressure gradient depends on all points in the stencil + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dP[ke] += dPresGrad_dP[ke] - dGravHead_dP[ke]; + dPhaseFlux_dP[ke] *= mobility; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[ke][jc] += dPresGrad_dC[ke][jc] - dGravHead_dC[ke][jc]; + dPhaseFlux_dC[ke][jc] *= mobility; + } + } + // compute phase flux using upwind mobility. + phaseFlux = mobility * potGrad; + + real64 const dMob_dP = dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dP]; + arraySlice1d< real64 const, compflow::USD_PHASE_DC - 2 > dPhaseMobSub = + dPhaseMob[er_up][esr_up][ei_up][ip]; + + // add contribution from upstream cell mobility derivatives + dPhaseFlux_dP[k_up] += dMob_dP * potGrad; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseFlux_dC[k_up][jc] += dPhaseMobSub[Deriv::dC+jc] * potGrad; + } + + //distribute on phaseComponentFlux here + PhaseComponentFlux::compute( ip, k_up, seri, sesri, sei, phaseCompFrac, dPhaseCompFrac, dCompFrac_dCompDens, phaseFlux + , dPhaseFlux_dP, dPhaseFlux_dC, compFlux, dCompFlux_dP, dCompFlux_dC ); + + } +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PPUPHASEFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp new file mode 100644 index 00000000000..812cc19eb3d --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp @@ -0,0 +1,128 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhaseComponentFlux.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASECOMPONENTFLUX_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASECOMPONENTFLUX_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "mesh/ElementRegionManager.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct PhaseComponentFlux +{ + /** + * @brief Compute the component flux for a given phase + * @tparam numComp number of components + * @tparam numFluxSupportPoints number of flux support points + * @param ip phase index + * @param k_up uptream index for this phase + * @param seri arraySlice of the stencil-implied element region index + * @param sesri arraySlice of the stencil-implied element subregion index + * @param sei arraySlice of the stencil-implied element index + * @param phaseCompFrac phase component fraction + * @param dPhaseCompFrac derivative of phase component fraction wrt pressure, temperature, component fraction + * @param dCompFrac_dCompDens derivative of component fraction wrt component density + * @param phaseFlux phase flux + * @param dPhaseFlux_dP derivative of phase flux wrt pressure + * @param dPhaseFlux_dC derivative of phase flux wrt comp density + * @param compFlux component flux + * @param dCompFlux_dP derivative of phase flux wrt pressure + * @param dCompFlux_dC derivative of phase flux wrt comp density + */ + template< localIndex numComp, localIndex numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute( localIndex const ip, + localIndex const k_up, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const & phaseCompFrac, + ElementViewConst< arrayView5d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC > > const & dPhaseCompFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + real64 const & phaseFlux, + real64 const ( &dPhaseFlux_dP )[numFluxSupportPoints], + real64 const ( &dPhaseFlux_dC )[numFluxSupportPoints][numComp], + real64 ( & compFlux )[numComp], + real64 ( & dCompFlux_dP )[numFluxSupportPoints][numComp], + real64 ( & dCompFlux_dC )[numFluxSupportPoints][numComp][numComp] ) + { + localIndex const er_up = seri[k_up]; + localIndex const esr_up = sesri[k_up]; + localIndex const ei_up = sei[k_up]; + + real64 dProp_dC[numComp]{}; + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP-3 > phaseCompFracSub = + phaseCompFrac[er_up][esr_up][ei_up][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC-3 > dPhaseCompFracSub = + dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; + + // compute component fluxes and derivatives using upstream cell composition + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + compFlux[ic] += phaseFlux * ycp; + + // derivatives stemming from phase flux + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dCompFlux_dP[ke][ic] += dPhaseFlux_dP[ke] * ycp; + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFlux_dC[ke][ic][jc] += dPhaseFlux_dC[ke][jc] * ycp; + } + } + + // additional derivatives stemming from upstream cell phase composition + dCompFlux_dP[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dP]; + + // convert derivatives of comp fraction w.r.t. comp fractions to derivatives w.r.t. comp densities + applyChainRule( numComp, + dCompFrac_dCompDens[er_up][esr_up][ei_up], + dPhaseCompFracSub[ic], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dCompFlux_dC[k_up][ic][jc] += phaseFlux * dProp_dC[jc]; + } + } + } +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASECOMPONENTFLUX_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp new file mode 100644 index 00000000000..1886cdbe4f5 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp @@ -0,0 +1,241 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhaseMobilityKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEMOBILITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEMOBILITYKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernels +{ + +/******************************** PhaseMobilityKernel ********************************/ + +/** + * @class PhaseMobilityKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_PHASE number of fluid phases + * @brief Defines the interface for the property kernel in charge of computing the phase mobilities + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseMobilityKernel : public isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP > +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::PropertyKernelBase< NUM_COMP >; + using Base::numComp; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NUM_PHASE; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] relperm the relperm model + */ + PhaseMobilityKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + : Base(), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ), + m_phaseVisc( fluid.phaseViscosity() ), + m_dPhaseVisc( fluid.dPhaseViscosity() ), + m_phaseRelPerm( relperm.phaseRelPerm() ), + m_dPhaseRelPerm_dPhaseVolFrac( relperm.dPhaseRelPerm_dPhaseVolFraction() ), + m_phaseMob( subRegion.getField< fields::flow::phaseMobility >() ), + m_dPhaseMob( subRegion.getField< fields::flow::dPhaseMobility >() ) + {} + + /** + * @brief Compute the phase mobilities 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] phaseMobilityKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void compute( localIndex const ei, + FUNC && phaseMobilityKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; + arraySlice1d< real64 const, constitutive::relperm::USD_RELPERM - 2 > const phaseRelPerm = m_phaseRelPerm[ei][0]; + arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; + arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseMob = m_phaseMob[ei]; + arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseMob = m_dPhaseMob[ei]; + + real64 dRelPerm_dC[numComp]{}; + real64 dDens_dC[numComp]{}; + real64 dVisc_dC[numComp]{}; + + for( integer ip = 0; ip < numPhase; ++ip ) + { + + // compute the phase mobility only if the phase is present + bool const phaseExists = (phaseVolFrac[ip] > 0); + if( !phaseExists ) + { + phaseMob[ip] = 0.0; + for( integer jc = 0; jc < numComp + 2; ++jc ) + { + dPhaseMob[ip][jc] = 0.0; + } + continue; + } + + real64 const density = phaseDens[ip]; + real64 const dDens_dP = dPhaseDens[ip][Deriv::dP]; + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dDens_dC, Deriv::dC ); + + real64 const viscosity = phaseVisc[ip]; + real64 const dVisc_dP = dPhaseVisc[ip][Deriv::dP]; + applyChainRule( numComp, dCompFrac_dCompDens, dPhaseVisc[ip], dVisc_dC, Deriv::dC ); + + real64 const relPerm = phaseRelPerm[ip]; + real64 dRelPerm_dP = 0.0; + for( integer ic = 0; ic < numComp; ++ic ) + { + dRelPerm_dC[ic] = 0.0; + } + + for( integer jp = 0; jp < numPhase; ++jp ) + { + real64 const dRelPerm_dS = dPhaseRelPerm_dPhaseVolFrac[ip][jp]; + dRelPerm_dP += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dP]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dRelPerm_dC[jc] += dRelPerm_dS * dPhaseVolFrac[jp][Deriv::dC+jc]; + } + } + + real64 const mobility = relPerm * density / viscosity; + + phaseMob[ip] = mobility; + dPhaseMob[ip][Deriv::dP] = dRelPerm_dP * density / viscosity + + mobility * (dDens_dP / density - dVisc_dP / viscosity); + + // compositional derivatives + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseMob[ip][Deriv::dC+jc] = dRelPerm_dC[jc] * density / viscosity + + mobility * (dDens_dC[jc] / density - dVisc_dC[jc] / viscosity); + } + + // call the lambda in the phase loop to allow the reuse of the relperm, density, viscosity, and mobility + // possible use: assemble the derivatives wrt temperature + phaseMobilityKernelOp( ip, phaseMob[ip], dPhaseMob[ip] ); + } + } + +protected: + + // inputs + + /// Views on the phase volume fractions + arrayView2d< real64 const, compflow::USD_PHASE > m_phaseVolFrac; + arrayView3d< real64 const, compflow::USD_PHASE_DC > m_dPhaseVolFrac; + arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; + + /// Views on the phase densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseDens; + + /// Views on the phase viscosities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseVisc; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseVisc; + + /// Views on the phase relative permeabilities + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > m_phaseRelPerm; + arrayView4d< real64 const, constitutive::relperm::USD_RELPERM_DS > m_dPhaseRelPerm_dPhaseVolFrac; + + // outputs + + /// Views on the phase mobilities + arrayView2d< real64, compflow::USD_PHASE > m_phaseMob; + arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseMob; + +}; + +/** + * @class PhaseMobilityKernelFactory + */ +class PhaseMobilityKernelFactory +{ +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 + * @param[in] relperm the relperm model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + { + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + } +}; + +} // namespace isothermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEMOBILITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp new file mode 100644 index 00000000000..875bfe07c8e --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp @@ -0,0 +1,256 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PhaseVolumeFractionKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEVOLUMEFRACTIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEVOLUMEFRACTIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** PhaseVolumeFractionKernel ********************************/ + +/** + * @class PhaseVolumeFractionKernel + * @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 phase volume fractions + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseVolumeFractionKernel : public PropertyKernelBase< NUM_COMP > +{ +public: + + using Base = PropertyKernelBase< NUM_COMP >; + using Base::numComp; + + /// Compile time value for the number of phases + static constexpr integer numPhase = NUM_PHASE; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + : Base(), + m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ), + m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ), + m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ), + m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ), + m_phaseFrac( fluid.phaseFraction() ), + m_dPhaseFrac( fluid.dPhaseFraction() ), + m_phaseDens( fluid.phaseDensity() ), + m_dPhaseDens( fluid.dPhaseDensity() ) + {} + + /** + * @brief Compute the phase volume fractions 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] phaseVolFractionKernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + real64 compute( localIndex const ei, + FUNC && phaseVolFractionKernelOp = NoOpFunc{} ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[ei]; + arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > const dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseFrac = m_phaseFrac[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; + arraySlice1d< real64, compflow::USD_PHASE - 1 > const phaseVolFrac = m_phaseVolFrac[ei]; + arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + real64 work[numComp]{}; + + // compute total density from component partial densities + real64 totalDensity = 0.0; + real64 const dTotalDens_dCompDens = 1.0; + for( integer ic = 0; ic < numComp; ++ic ) + { + totalDensity += compDens[ic]; + } + + real64 maxDeltaPhaseVolFrac = 0.0; + + for( integer ip = 0; ip < numPhase; ++ip ) + { + + // set the saturation to zero if the phase is absent + bool const phaseExists = (phaseFrac[ip] > 0); + if( !phaseExists ) + { + phaseVolFrac[ip] = 0.; + for( integer jc = 0; jc < numComp+2; ++jc ) + { + dPhaseVolFrac[ip][jc] = 0.; + } + continue; + } + + // Expression for volume fractions: S_p = (nu_p / rho_p) * rho_t + real64 const phaseDensInv = 1.0 / phaseDens[ip]; + + // store old saturation to compute change later + real64 const satOld = phaseVolFrac[ip]; + + // compute saturation and derivatives except multiplying by the total density + phaseVolFrac[ip] = phaseFrac[ip] * phaseDensInv; + + dPhaseVolFrac[ip][Deriv::dP] = + (dPhaseFrac[ip][Deriv::dP] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP]) * phaseDensInv; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseVolFrac[ip][Deriv::dC+jc] = + (dPhaseFrac[ip][Deriv::dC+jc] - phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dC+jc]) * phaseDensInv; + } + + // apply chain rule to convert derivatives from global component fractions to densities + applyChainRuleInPlace( numComp, dCompFrac_dCompDens, dPhaseVolFrac[ip], work, Deriv::dC ); + + // call the lambda in the phase loop to allow the reuse of the phaseVolFrac and totalDensity + // possible use: assemble the derivatives wrt temperature + phaseVolFractionKernelOp( ip, phaseVolFrac[ip], phaseDensInv, totalDensity ); + + // now finalize the computation by multiplying by total density + for( integer jc = 0; jc < numComp; ++jc ) + { + dPhaseVolFrac[ip][Deriv::dC+jc] *= totalDensity; + dPhaseVolFrac[ip][Deriv::dC+jc] += phaseVolFrac[ip] * dTotalDens_dCompDens; + } + + phaseVolFrac[ip] *= totalDensity; + dPhaseVolFrac[ip][Deriv::dP] *= totalDensity; + + real64 const deltaPhaseVolFrac = LvArray::math::abs( phaseVolFrac[ip] - satOld ); + if( maxDeltaPhaseVolFrac < deltaPhaseVolFrac ) + { + maxDeltaPhaseVolFrac = deltaPhaseVolFrac; + } + } + return maxDeltaPhaseVolFrac; + } + + /** + * @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 the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static real64 + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPhaseVolFrac( 0.0 ); + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + real64 const deltaPhaseVolFrac = kernelComponent.compute( ei ); + maxDeltaPhaseVolFrac.max( deltaPhaseVolFrac ); + } ); + return maxDeltaPhaseVolFrac.get(); + } + +protected: + + // outputs + + /// Views on phase volume fractions + arrayView2d< real64, compflow::USD_PHASE > m_phaseVolFrac; + arrayView3d< real64, compflow::USD_PHASE_DC > m_dPhaseVolFrac; + + // inputs + + /// Views on component densities + arrayView2d< real64 const, compflow::USD_COMP > m_compDens; + arrayView3d< real64 const, compflow::USD_COMP_DC > m_dCompFrac_dCompDens; + + /// Views on phase fractions + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseFrac; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseFrac; + + /// Views on phase densities + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseDens; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseDens; + +}; + +/** + * @class PhaseVolumeFractionKernelFactory + */ +class PhaseVolumeFractionKernelFactory +{ +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 real64 + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + { + real64 maxDeltaPhaseVolFrac = 0.0; + if( numPhase == 2 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + return maxDeltaPhaseVolFrac; + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PHASEVOLUMEFRACTIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp new file mode 100644 index 00000000000..14f702792db --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp @@ -0,0 +1,208 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PotGrad.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_POTGRAD_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_POTGRAD_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "constitutive/fluid/multifluid/Layouts.hpp" +#include "constitutive/capillaryPressure/layouts.hpp" +#include "mesh/ElementRegionManager.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseFVMKernelUtilities +{ + +template< typename VIEWTYPE > +using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + +using Deriv = constitutive::multifluid::DerivativeOffset; + +struct PotGrad +{ + template< integer numComp, integer numFluxSupportPoints > + GEOS_HOST_DEVICE + static void + compute ( integer const numPhase, + integer const ip, + integer const hasCapPressure, + localIndex const ( &seri )[numFluxSupportPoints], + localIndex const ( &sesri )[numFluxSupportPoints], + localIndex const ( &sei )[numFluxSupportPoints], + real64 const ( &trans )[numFluxSupportPoints], + real64 const ( &dTrans_dPres )[numFluxSupportPoints], + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const & phaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_PHASE_DC > > const & dPhaseVolFrac, + ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const & dCompFrac_dCompDens, + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const & phaseMassDens, + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const & dPhaseMassDens, + ElementViewConst< arrayView3d< real64 const, constitutive::cappres::USD_CAPPRES > > const & phaseCapPressure, + ElementViewConst< arrayView4d< real64 const, constitutive::cappres::USD_CAPPRES_DS > > const & dPhaseCapPressure_dPhaseVolFrac, + real64 & potGrad, + real64 ( & dPresGrad_dP )[numFluxSupportPoints], + real64 ( & dPresGrad_dC )[numFluxSupportPoints][numComp], + real64 ( & dGravHead_dP )[numFluxSupportPoints], + real64 ( & dGravHead_dC )[numFluxSupportPoints][numComp] ) + { + // assign derivatives arrays to zero + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + dPresGrad_dP[i] = 0.0; + dGravHead_dP[i] = 0.0; + for( integer jc = 0; jc < numComp; ++jc ) + { + dPresGrad_dC[i][jc] = 0.0; + dGravHead_dC[i][jc] = 0.0; + } + } + + // create local work arrays + real64 densMean = 0.0; + real64 dDensMean_dP[numFluxSupportPoints]{}; + real64 dDensMean_dC[numFluxSupportPoints][numComp]{}; + + real64 presGrad = 0.0; + real64 gravHead = 0.0; + real64 dCapPressure_dC[numComp]{}; + + real64 dProp_dC[numComp]{}; + + // calculate quantities on primary connected cells + integer denom = 0; + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + bool const phaseExists = (phaseVolFrac[er][esr][ei][ip] > 0); + if( !phaseExists ) + { + continue; + } + + // density + real64 const density = phaseMassDens[er][esr][ei][0][ip]; + real64 const dDens_dP = dPhaseMassDens[er][esr][ei][0][ip][Deriv::dP]; + + applyChainRule( numComp, + dCompFrac_dCompDens[er][esr][ei], + dPhaseMassDens[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + + // average density and derivatives + densMean += density; + dDensMean_dP[i] = dDens_dP; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDensMean_dC[i][jc] = dProp_dC[jc]; + } + denom++; + } + if( denom > 1 ) + { + densMean /= denom; + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + dDensMean_dP[i] /= denom; + for( integer jc = 0; jc < numComp; ++jc ) + { + dDensMean_dC[i][jc] /= denom; + } + } + } + + /// compute the TPFA potential difference + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + // capillary pressure + real64 capPressure = 0.0; + real64 dCapPressure_dP = 0.0; + + for( integer ic = 0; ic < numComp; ++ic ) + { + dCapPressure_dC[ic] = 0.0; + } + + if( hasCapPressure ) + { + capPressure = phaseCapPressure[er][esr][ei][0][ip]; + + for( integer jp = 0; jp < numPhase; ++jp ) + { + real64 const dCapPressure_dS = dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dCapPressure_dP += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dP]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dCapPressure_dC[jc] += dCapPressure_dS * dPhaseVolFrac[er][esr][ei][jp][Deriv::dC+jc]; + } + } + } + + presGrad += trans[i] * (pres[er][esr][ei] - capPressure); + dPresGrad_dP[i] += trans[i] * (1 - dCapPressure_dP) + + dTrans_dPres[i] * (pres[er][esr][ei] - capPressure); + for( integer jc = 0; jc < numComp; ++jc ) + { + dPresGrad_dC[i][jc] += -trans[i] * dCapPressure_dC[jc]; + } + + real64 const gravD = trans[i] * gravCoef[er][esr][ei]; + real64 const dGravD_dP = dTrans_dPres[i] * gravCoef[er][esr][ei]; + + // the density used in the potential difference is always a mass density + // unlike the density used in the phase mobility, which is a mass density + // if useMass == 1 and a molar density otherwise + gravHead += densMean * gravD; + + // need to add contributions from both cells the mean density depends on + for( integer j = 0; j < numFluxSupportPoints; ++j ) + { + dGravHead_dP[j] += dDensMean_dP[j] * gravD + dGravD_dP * densMean; + for( integer jc = 0; jc < numComp; ++jc ) + { + dGravHead_dC[j][jc] += dDensMean_dC[j][jc] * gravD; + } + } + } + + // compute phase potential gradient + potGrad = presGrad - gravHead; + + } + +}; + +} // namespace isothermalCompositionalMultiPhaseFVMKernelUtilities + +} // namespace geos + +#endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_POTGRAD_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp new file mode 100644 index 00000000000..4390ad8a34b --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp @@ -0,0 +1,91 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file PropertyKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PROPERTYKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PROPERTYKERNELBASE_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** PropertyKernelBase ********************************/ + +/** + * @class PropertyKernelBase + * @tparam NUM_COMP number of fluid components + * @brief Define the base interface for the property update kernels + */ +template< integer NUM_COMP > +class PropertyKernelBase +{ +public: + + /// Compile time value for the number of components + static constexpr integer numComp = NUM_COMP; + + /** + * @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 the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + kernelComponent.compute( ei ); + } ); + } + + /** + * @brief Performs the kernel launch on a sorted array + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] targetSet the indices of the elements in which we compute the property + * @param[inout] kernelComponent the kernel component providing access to the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + KERNEL_TYPE const & kernelComponent ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) + { + localIndex const ei = targetSet[ i ]; + kernelComponent.compute( ei ); + } ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_PROPERTYKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ReactiveCompositionalMultiphaseOBLKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp similarity index 96% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/ReactiveCompositionalMultiphaseOBLKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp index 168bb83da93..bc76898511d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ReactiveCompositionalMultiphaseOBLKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp @@ -584,13 +584,13 @@ class ElementBasedAssemblyKernelFactory }; -/******************************** FaceBasedAssemblyKernel ********************************/ +/******************************** FluxComputeKernel ********************************/ /** - * @brief Base class for FaceBasedAssemblyKernel that holds all data not dependent + * @brief Base class for FluxComputeKernel that holds all data not dependent * on template parameters (like stencil type and number of components/dofs). * - * FaceBasedAssemblyKernel is used for flux terms calculation. + * FluxComputeKernel is used for flux terms calculation. * In case mesh geometry/configuration is not changing during simulation, * all connections can be pre-computed, sorted by element, and stored. * Then, ElementBasedAssemblyKernel can be used for flux calculation: every flux will be computed twice, @@ -598,7 +598,7 @@ class ElementBasedAssemblyKernelFactory * and therefore overall performance can significantly improve * */ -class FaceBasedAssemblyKernelBase +class FluxComputeKernelBase { public: @@ -656,14 +656,14 @@ class FaceBasedAssemblyKernelBase * @param[inout] localMatrix the local CRS matrix * @param[inout] localRhs the local right-hand side vector */ - FaceBasedAssemblyKernelBase( globalIndex const rankOffset, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - real64 const & transMultExp, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) + FluxComputeKernelBase( globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + real64 const & transMultExp, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) : m_rankOffset( rankOffset ), m_dt( dt * secondsToDaysMult ), m_transMultExp ( transMultExp ), @@ -724,7 +724,7 @@ class FaceBasedAssemblyKernelBase }; /** - * @class FaceBasedAssemblyKernel + * @class FluxComputeKernel * @tparam NUM_PHASES number of phases * @tparam NUM_COMPS number of components * @tparam ENABLE_ENERGY flag if energy balance equation is assembled @@ -732,7 +732,7 @@ class FaceBasedAssemblyKernelBase * @brief Compute flux term for an element */ template< integer NUM_PHASES, integer NUM_COMPS, bool ENABLE_ENERGY, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase +class FluxComputeKernel : public FluxComputeKernelBase { public: @@ -790,23 +790,23 @@ class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase * @param[inout] localMatrix the local CRS matrix * @param[inout] localRhs the local right-hand side vector */ - FaceBasedAssemblyKernel( globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - real64 const & transMultExp, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - : FaceBasedAssemblyKernelBase( rankOffset, - dofNumberAccessor, - compFlowAccessors, - permeabilityAccessors, - dt, - transMultExp, - localMatrix, - localRhs ), + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + real64 const & transMultExp, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : FluxComputeKernelBase( rankOffset, + dofNumberAccessor, + compFlowAccessors, + permeabilityAccessors, + dt, + transMultExp, + localMatrix, + localRhs ), m_stencilWrapper( stencilWrapper ), m_seri( stencilWrapper.getElementRegionIndices() ), m_sesri( stencilWrapper.getElementSubRegionIndices() ), @@ -1168,9 +1168,9 @@ class FaceBasedAssemblyKernel : public FaceBasedAssemblyKernelBase }; /** - * @class FaceBasedAssemblyKernelFactory + * @class FluxComputeKernelFactory */ -class FaceBasedAssemblyKernelFactory +class FluxComputeKernelFactory { public: @@ -1216,7 +1216,7 @@ class FaceBasedAssemblyKernelFactory elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - using KERNEL_TYPE = FaceBasedAssemblyKernel< NUM_PHASES, NUM_COMPS, ENABLE_ENERGY, STENCILWRAPPER >; + using KERNEL_TYPE = FluxComputeKernel< NUM_PHASES, NUM_COMPS, ENABLE_ENERGY, STENCILWRAPPER >; typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); typename KERNEL_TYPE::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp new file mode 100644 index 00000000000..7706d28b679 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp @@ -0,0 +1,73 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file RelativePermeabilityUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RELATIVEPERMEABILITYUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RELATIVEPERMEABILITYUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** RelativePermeabilityUpdateKernel ********************************/ + +struct RelativePermeabilityUpdateKernel +{ + template< typename POLICY, typename RELPERM_WRAPPER > + static void + launch( localIndex const size, + RELPERM_WRAPPER const & relPermWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) + { + relPermWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } + + template< typename POLICY, typename RELPERM_WRAPPER > + static void + launch( SortedArrayView< localIndex const > const & targetSet, + RELPERM_WRAPPER const & relPermWrapper, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac ) + { + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + localIndex const k = targetSet[a]; + for( localIndex q = 0; q < relPermWrapper.numGauss(); ++q ) + { + relPermWrapper.update( k, q, phaseVolFrac[k] ); + } + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RELATIVEPERMEABILITYUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp new file mode 100644 index 00000000000..b5d4d8c0ae0 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp @@ -0,0 +1,191 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ResidualNormKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RESIDUALNORMKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RESIDUALNORMKERNEL_HPP + +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class ResidualNormKernel + */ +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 > +{ +public: + + using Base = physicsSolverBaseKernels::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 numComponents, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_numComponents( numComponents ), + m_volume( subRegion.getElementVolume() ), + m_porosity_n( solid.getPorosity_n() ), + m_totalDens_n( fluid.totalDensity_n() ) + {} + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + // this should never be zero if the simulation is set up correctly, but we never know + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); + real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); + + // step 1: mass residuals + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + } + + // step 2: volume residual + + real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; + if( valVol > stack.localValue[1] ) + { + stack.localValue[1] = valVol; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + // note: for the L2 norm, we bundle the volume and mass residuals/normalizers + + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); + + // step 1: mass residuals + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; + stack.localNormalizer[0] += massNormalizer; + } + + // step 2: volume residual + + real64 const val = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the + // multiplication + stack.localValue[1] += val * val; + stack.localNormalizer[1] += massNormalizer; + } + + +protected: + + /// Number of fluid coponents + integer const m_numComponents; + + /// View on the volume + arrayView1d< real64 const > const m_volume; + + /// View on porosity at the previous converged time step + arrayView2d< real64 const > const m_porosity_n; + + /// View on total mass/molar density at the previous converged time step + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const m_totalDens_n; + +}; + +/** + * @class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @param[in] numComps the number of fluid components + * @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 element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + integer const numComps, + globalIndex const rankOffset, + string const dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + real64 const minNormalizer, + real64 (& residualNorm)[2], + real64 (& residualNormalizer)[2] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, numComps, subRegion, fluid, solid, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_RESIDUALNORMKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp new file mode 100644 index 00000000000..67a37d81282 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp @@ -0,0 +1,55 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidInternalEnergyUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLIDINTERNALENERGYUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLIDINTERNALENERGYUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolidInternalEnergyUpdateKernel ********************************/ + +struct SolidInternalEnergyUpdateKernel +{ + + template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > + static void + launch( localIndex const size, + SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, + arrayView1d< real64 const > const & temp ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + solidInternalEnergyWrapper.update( k, temp[k] ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLIDINTERNALENERGYUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp new file mode 100644 index 00000000000..63b5975dd7a --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp @@ -0,0 +1,334 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionCheckKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONCHECKKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONCHECKKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionCheckKernel ********************************/ + +/** + * @class SolutionCheckKernel + * @brief Define the kernel for checking the updated solution + */ +class SolutionCheckKernel : public SolutionScalingAndCheckingKernelBase< integer > +{ +public: + + using Base = SolutionScalingAndCheckingKernelBase< integer >; + using Base::m_rankOffset; + using Base::m_numComp; + using Base::m_dofNumber; + using Base::m_ghostRank; + using Base::m_localSolution; + using Base::m_pressure; + using Base::m_compDens; + + /** + * @brief Create a new kernel instance + * @param[in] allowCompDensChopping flag to allow the component density chopping + * @param[in] scalingFactor the scaling factor + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] compDens the component density vector + */ + SolutionCheckKernel( integer const allowCompDensChopping, + 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 ) + : Base( rankOffset, + numComp, + dofKey, + subRegion, + localSolution, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor ), + m_allowCompDensChopping( allowCompDensChopping ), + m_allowNegativePressure( allowNegativePressure ), + m_scalingFactor( scalingFactor ), + m_scalingType( scalingType ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables : public Base::StackVariables + { + GEOS_HOST_DEVICE + StackVariables() + { } + + StackVariables( real64 _localMinVal, + real64 _localMinPres, + real64 _localMinDens, + real64 _localMinTotalDens, + integer _localNumNegPressures, + integer _localNumNegDens, + integer _localNumNegTotalDens ) + : + Base::StackVariables( _localMinVal ), + localMinPres( _localMinPres ), + localMinDens( _localMinDens ), + localMinTotalDens( _localMinTotalDens ), + localNumNegPressures( _localNumNegPressures ), + localNumNegDens( _localNumNegDens ), + localNumNegTotalDens( _localNumNegTotalDens ) + { } + + real64 localMinPres; + real64 localMinDens; + real64 localMinTotalDens; + + integer localNumNegPressures; + integer localNumNegDens; + integer localNumNegTotalDens; + + }; + + /** + * @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 the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static StackVariables + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, integer > globalMinVal( 1 ); + + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minDens( 0.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTotalDens( 0.0 ); + + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegPressures( 0 ); + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegDens( 0 ); + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegTotalDens( 0 ); + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.ghostRank( ei ) >= 0 ) + { + return; + } + + StackVariables stack; + kernelComponent.setup( ei, stack ); + kernelComponent.compute( ei, stack ); + + globalMinVal.min( stack.localMinVal ); + + minPres.min( stack.localMinPres ); + minDens.min( stack.localMinDens ); + minTotalDens.min( stack.localMinTotalDens ); + + numNegPressures += stack.localNumNegPressures; + numNegDens += stack.localNumNegDens; + numNegTotalDens += stack.localNumNegTotalDens; + } ); + + return StackVariables( globalMinVal.get(), + minPres.get(), + minDens.get(), + minTotalDens.get(), + numNegPressures.get(), + numNegDens.get(), + numNegTotalDens.get() ); + } + + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + stack.localMinPres = 0.0; + stack.localMinDens = 0.0; + stack.localMinTotalDens = 0.0; + + stack.localNumNegPressures = 0; + stack.localNumNegDens = 0; + stack.localNumNegTotalDens = 0; + } + + /** + * @brief Compute the local value + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void compute( localIndex const ei, + StackVariables & stack ) const + { + computeSolutionCheck( ei, stack ); + } + + /** + * @brief Compute the local value of the check + * @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] kernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeSolutionCheck( localIndex const ei, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + bool const localScaling = m_scalingType == CompositionalMultiphaseFVM::ScalingType::Local; + + real64 const newPres = m_pressure[ei] + (localScaling ? m_pressureScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow]; + if( newPres < 0 ) + { + if( !m_allowNegativePressure ) + { + stack.localMinVal = 0; + } + stack.localNumNegPressures += 1; + if( newPres < stack.localMinPres ) + stack.localMinPres = newPres; + } + + // if component density chopping is not allowed, the time step fails if a component density is negative + // otherwise, we just check that the total density is positive, and negative component densities + // will be chopped (i.e., set to zero) in ApplySystemSolution) + if( !m_allowCompDensChopping ) + { + for( integer ic = 0; ic < m_numComp; ++ic ) + { + real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; + if( newDens < 0 ) + { + stack.localMinVal = 0; + stack.localNumNegDens += 1; + if( newDens < stack.localMinDens ) + stack.localMinDens = newDens; + } + } + } + else + { + real64 totalDens = 0.0; + for( integer ic = 0; ic < m_numComp; ++ic ) + { + real64 const newDens = m_compDens[ei][ic] + (localScaling ? m_compDensScalingFactor[ei] : m_scalingFactor) * m_localSolution[stack.localRow + ic + 1]; + totalDens += ( newDens > 0.0 ) ? newDens : 0.0; + } + if( totalDens < 0 ) + { + stack.localMinVal = 0; + stack.localNumNegTotalDens += 1; + if( totalDens < stack.localMinTotalDens ) + stack.localMinTotalDens = totalDens; + } + } + + kernelOp(); + } + +protected: + + /// flag to allow the component density chopping + integer const m_allowCompDensChopping; + + /// flag to allow negative pressure values + integer const m_allowNegativePressure; + + /// scaling factor + real64 const m_scalingFactor; + + /// scaling type (global or local) + CompositionalMultiphaseFVM::ScalingType const m_scalingType; + +}; + +/** + * @class SolutionCheckKernelFactory + */ +class SolutionCheckKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] allowCompDensChopping flag to allow the component density chopping + * @param[in] scalingFactor the scaling factor + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static SolutionCheckKernel::StackVariables + createAndLaunch( integer const allowCompDensChopping, + 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 ) + { + SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, + pressure, compDens, pressureScalingFactor, compDensScalingFactor, rankOffset, + numComp, dofKey, subRegion, localSolution ); + return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONCHECKKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp new file mode 100644 index 00000000000..ff03cf15f71 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp @@ -0,0 +1,182 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionScalingAndCheckingKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGANDCHECKINGKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGANDCHECKINGKERNELBASE_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "mesh/ElementSubRegionBase.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/** + * @class SolutionScalingAndCheckingKernelBase + * @brief Define the kernel for scaling the solution and check its validity + */ +template< typename TYPE > +class SolutionScalingAndCheckingKernelBase +{ +public: + + /** + * @brief Create a new kernel instance + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] compDens the component density vector + * @param[in] pressureScalingFactor the pressure local scaling factor + * @param[in] compDensScalingFactor the component local scaling factor + */ + SolutionScalingAndCheckingKernelBase( 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 ) + : m_rankOffset( rankOffset ), + m_numComp( numComp ), + m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ), + m_ghostRank( subRegion.ghostRank() ), + m_localSolution( localSolution ), + m_pressure( pressure ), // not passed with fields::flow to be able to reuse this for wells + m_compDens( compDens ), // same here + m_pressureScalingFactor( pressureScalingFactor ), + m_compDensScalingFactor( compDensScalingFactor ) + { } + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables + { + GEOS_HOST_DEVICE + StackVariables() + { } + + StackVariables( real64 _localMinVal ) + : + localMinVal( _localMinVal ) + { } + + /// Index of the local row corresponding to this element + localIndex localRow; + + /// The local value + TYPE localMinVal; + }; + + /** + * @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 + { + stack.localMinVal = 1; + + // set row index and degrees of freedom indices for this element + stack.localRow = m_dofNumber[ei] - m_rankOffset; + } + + /** + * @brief Getter for the ghost rank + * @param[in] i the looping index of the element/node/face + * @return the ghost rank of the element/node/face + */ + GEOS_HOST_DEVICE + integer ghostRank( localIndex const i ) const + { return m_ghostRank( i ); } + + /** + * @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 the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static TYPE + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, TYPE > minVal( 1 ); + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.ghostRank( ei ) >= 0 ) + { + return; + } + + StackVariables stack; + kernelComponent.setup( ei, stack ); + kernelComponent.compute( ei, stack ); + minVal.min( stack.localMinVal ); + } ); + + return minVal.get(); + } + +protected: + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// Number of components + real64 const m_numComp; + + /// View on the dof numbers + arrayView1d< globalIndex const > const m_dofNumber; + + /// View on the ghost ranks + arrayView1d< integer const > const m_ghostRank; + + /// View on the local residual + arrayView1d< real64 const > const m_localSolution; + + /// View on the primary variables + arrayView1d< real64 const > const m_pressure; + arrayView2d< real64 const, compflow::USD_COMP > const m_compDens; + + /// View on the scaling factors + arrayView1d< real64 > const m_pressureScalingFactor; + arrayView1d< real64 > const m_compDensScalingFactor; + +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGANDCHECKINGKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp new file mode 100644 index 00000000000..3158d2f7537 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp @@ -0,0 +1,383 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionScalingKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseFVM.hpp" + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionScalingKernel ********************************/ + +/** + * @class SolutionScalingKernel + * @brief Define the kernel for scaling the Newton update + */ +class SolutionScalingKernel : public SolutionScalingAndCheckingKernelBase< real64 > +{ +public: + + using Base = SolutionScalingAndCheckingKernelBase< real64 >; + using Base::m_rankOffset; + using Base::m_numComp; + using Base::m_dofNumber; + using Base::m_ghostRank; + using Base::m_localSolution; + using Base::m_pressure; + using Base::m_compDens; + using Base::m_pressureScalingFactor; + using Base::m_compDensScalingFactor; + + /** + * @brief Create a new kernel instance + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompDensChange the max allowed comp density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] compDens the component density vector + * @param[in] pressureScalingFactor the pressure local scaling factor + * @param[in] compDensScalingFactor the component density local scaling factor + */ + SolutionScalingKernel( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + 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 ) + : Base( rankOffset, + numComp, + dofKey, + subRegion, + localSolution, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor ), + m_maxRelativePresChange( maxRelativePresChange ), + m_maxAbsolutePresChange( maxAbsolutePresChange ), + m_maxCompFracChange( maxCompFracChange ), + m_maxRelativeCompDensChange( maxRelativeCompDensChange ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables located on the stack + */ + struct StackVariables : public Base::StackVariables + { + GEOS_HOST_DEVICE + StackVariables() + { } + + StackVariables( real64 _localMinVal, + real64 _localMaxDeltaPres, + real64 _localMaxDeltaTemp, + real64 _localMaxDeltaCompDens, + real64 _localMinPresScalingFactor, + real64 _localMinTempScalingFactor, + real64 _localMinCompDensScalingFactor ) + : + Base::StackVariables( _localMinVal ), + localMaxDeltaPres( _localMaxDeltaPres ), + localMaxDeltaTemp( _localMaxDeltaTemp ), + localMaxDeltaCompDens( _localMaxDeltaCompDens ), + localMinPresScalingFactor( _localMinPresScalingFactor ), + localMinTempScalingFactor( _localMinTempScalingFactor ), + localMinCompDensScalingFactor( _localMinCompDensScalingFactor ) + { } + + real64 localMaxDeltaPres; + real64 localMaxDeltaTemp; + real64 localMaxDeltaCompDens; + + real64 localMinPresScalingFactor; + real64 localMinTempScalingFactor; + real64 localMinCompDensScalingFactor; + + }; + + /** + * @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 the compute function + */ + template< typename POLICY, typename KERNEL_TYPE > + static StackVariables + launch( localIndex const numElems, + KERNEL_TYPE const & kernelComponent ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > globalScalingFactor( 1.0 ); + + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPres( 0.0 ); + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaTemp( 0.0 ); + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaCompDens( 0.0 ); + + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPresScalingFactor( 1.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minTempScalingFactor( 1.0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minCompDensScalingFactor( 1.0 ); + + forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( kernelComponent.ghostRank( ei ) >= 0 ) + { + return; + } + + StackVariables stack; + kernelComponent.setup( ei, stack ); + kernelComponent.compute( ei, stack ); + + globalScalingFactor.min( stack.localMinVal ); + + maxDeltaPres.max( stack.localMaxDeltaPres ); + maxDeltaTemp.max( stack.localMaxDeltaTemp ); + maxDeltaCompDens.max( stack.localMaxDeltaCompDens ); + + minPresScalingFactor.min( stack.localMinPresScalingFactor ); + minTempScalingFactor.min( stack.localMinTempScalingFactor ); + minCompDensScalingFactor.min( stack.localMinCompDensScalingFactor ); + } ); + + return StackVariables( globalScalingFactor.get(), + maxDeltaPres.get(), + maxDeltaTemp.get(), + maxDeltaCompDens.get(), + minPresScalingFactor.get(), + minTempScalingFactor.get(), + minCompDensScalingFactor.get() ); + } + + GEOS_HOST_DEVICE + void setup( localIndex const ei, + StackVariables & stack ) const + { + Base::setup( ei, stack ); + + stack.localMaxDeltaPres = 0.0; + stack.localMaxDeltaTemp = 0.0; + stack.localMaxDeltaCompDens = 0.0; + + stack.localMinPresScalingFactor = 1.0; + stack.localMinTempScalingFactor = 1.0; + stack.localMinCompDensScalingFactor = 1.0; + } + + /** + * @brief Compute the local value + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void compute( localIndex const ei, + StackVariables & stack ) const + { + computeScalingFactor( ei, stack ); + } + + /** + * @brief Compute the local value of the scaling factor + * @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] kernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeScalingFactor( localIndex const ei, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + real64 constexpr eps = minDensForDivision; + + // compute the change in pressure + real64 const pres = m_pressure[ei]; + real64 const absPresChange = LvArray::math::abs( m_localSolution[stack.localRow] ); + if( stack.localMaxDeltaPres < absPresChange ) + { + stack.localMaxDeltaPres = absPresChange; + } + + // compute pressure scaling factor + real64 presScalingFactor = 1.0; + // when enabled, absolute change scaling has a priority over relative change + if( m_maxAbsolutePresChange > 0.0 ) // maxAbsolutePresChange <= 0.0 means that absolute scaling is disabled + { + if( absPresChange > m_maxAbsolutePresChange ) + { + presScalingFactor = m_maxAbsolutePresChange / absPresChange; + } + } + else if( pres > eps ) + { + real64 const relativePresChange = absPresChange / pres; + if( relativePresChange > m_maxRelativePresChange ) + { + presScalingFactor = m_maxRelativePresChange / relativePresChange; + } + } + m_pressureScalingFactor[ei] = presScalingFactor; + if( stack.localMinVal > presScalingFactor ) + { + stack.localMinVal = presScalingFactor; + } + if( stack.localMinPresScalingFactor > presScalingFactor ) + { + stack.localMinPresScalingFactor = presScalingFactor; + } + + real64 prevTotalDens = 0; + for( integer ic = 0; ic < m_numComp; ++ic ) + { + prevTotalDens += m_compDens[ei][ic]; + } + + m_compDensScalingFactor[ei] = 1.0; + + // compute the change in component densities and component fractions + for( integer ic = 0; ic < m_numComp; ++ic ) + { + // compute scaling factor based on relative change in component densities + real64 const absCompDensChange = LvArray::math::abs( m_localSolution[stack.localRow + ic + 1] ); + if( stack.localMaxDeltaCompDens < absCompDensChange ) + { + stack.localMaxDeltaCompDens = absCompDensChange; + } + + // This actually checks the change in component fraction, using a lagged total density + // Indeed we can rewrite the following check as: + // | prevCompDens / prevTotalDens - newCompDens / prevTotalDens | > maxCompFracChange + // Note that the total density in the second term is lagged (i.e, we use prevTotalDens) + // because I found it more robust than using directly newTotalDens (which can vary also + // wildly when the compDens change is large) + real64 const maxAbsCompDensChange = m_maxCompFracChange * prevTotalDens; + if( absCompDensChange > maxAbsCompDensChange && absCompDensChange > eps ) + { + real64 const compScalingFactor = maxAbsCompDensChange / absCompDensChange; + m_compDensScalingFactor[ei] = LvArray::math::min( m_compDensScalingFactor[ei], compScalingFactor ); + if( stack.localMinVal > compScalingFactor ) + { + stack.localMinVal = compScalingFactor; + } + if( stack.localMinCompDensScalingFactor > compScalingFactor ) + { + stack.localMinCompDensScalingFactor = compScalingFactor; + } + } + + // switch from relative to absolute when value is < 1.0 + real64 const maxRelCompDensChange = m_maxRelativeCompDensChange * LvArray::math::max( m_compDens[ei][ic], 1.0 ); + if( absCompDensChange > maxRelCompDensChange && absCompDensChange > eps ) + { + real64 const compScalingFactor = maxRelCompDensChange / absCompDensChange; + m_compDensScalingFactor[ei] = LvArray::math::min( m_compDensScalingFactor[ei], compScalingFactor ); + if( stack.localMinVal > compScalingFactor ) + { + stack.localMinVal = compScalingFactor; + } + if( stack.localMinCompDensScalingFactor > compScalingFactor ) + { + stack.localMinCompDensScalingFactor = compScalingFactor; + } + } + } + + // compute the scaling factor for other vars, such as temperature + kernelOp(); + } + +protected: + + /// Max allowed changes in primary variables + real64 const m_maxRelativePresChange; + real64 const m_maxAbsolutePresChange; + real64 const m_maxCompFracChange; + real64 const m_maxRelativeCompDensChange; + +}; + +/** + * @class SolutionScalingKernelFactory + */ +class SolutionScalingKernelFactory +{ +public: + + /* + * @brief Create and launch the kernel computing the scaling factor + * @tparam POLICY the kernel policy + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompDensChange the max allowed comp density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @return the scaling factor + */ + template< typename POLICY > + static SolutionScalingKernel::StackVariables + createAndLaunch( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + 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 ) + { + SolutionScalingKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, maxRelativeCompDensChange, rankOffset, + numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); + return SolutionScalingKernel::launch< POLICY >( subRegion.size(), kernel ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_SOLUTIONSCALINGKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/StabilizedCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp similarity index 86% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/StabilizedCompositionalMultiphaseFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp index 7e249ed0ab7..de9e92c8b80 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/StabilizedCompositionalMultiphaseFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp @@ -14,13 +14,15 @@ */ /** - * @file StabilizedCompositionalMultiphaseFVMKernels.hpp + * @file StabilizedFluxComputeKernel.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STABILIZEDFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STABILIZEDFLUXCOMPUTEKERNEL_HPP -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityFields.hpp" namespace geos { @@ -28,17 +30,17 @@ namespace geos namespace stabilizedCompositionalMultiphaseFVMKernels { -/******************************** FaceBasedAssemblyKernel ********************************/ +/******************************** FluxComputeKernel ********************************/ /** - * @class FaceBasedAssemblyKernel + * @class FluxComputeKernel * @tparam NUM_COMP number of fluid components * @tparam NUM_DOF number of degrees of freedom * @tparam STENCILWRAPPER the type of the stencil wrapper * @brief Define the interface for the assembly kernel in charge of flux terms */ template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +class FluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > { public: @@ -51,7 +53,7 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using CompFlowAccessors = AbstractBase::CompFlowAccessors; using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; @@ -82,7 +84,7 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne using AbstractBase::m_dCompFrac_dCompDens; using AbstractBase::m_pres; - using Base = isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; using Base::numComp; using Base::numDof; using Base::numEqn; @@ -115,21 +117,21 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne * @param[inout] localRhs the local right-hand side vector * @param[in] kernelFlags flags packed together */ - FaceBasedAssemblyKernel( integer const numPhases, - globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - CompFlowAccessors const & compFlowAccessors, - StabCompFlowAccessors const & stabCompFlowAccessors, - MultiFluidAccessors const & multiFluidAccessors, - StabMultiFluidAccessors const & stabMultiFluidAccessors, - CapPressureAccessors const & capPressureAccessors, - PermeabilityAccessors const & permeabilityAccessors, - RelPermAccessors const & relPermAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags ) + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + StabCompFlowAccessors const & stabCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + StabMultiFluidAccessors const & stabMultiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + RelPermAccessors const & relPermAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) : Base( numPhases, rankOffset, stencilWrapper, @@ -296,9 +298,9 @@ class FaceBasedAssemblyKernel : public isothermalCompositionalMultiphaseFVMKerne }; /** - * @class FaceBasedAssemblyKernelFactory + * @class FluxComputeKernelFactory */ -class FaceBasedAssemblyKernelFactory +class FluxComputeKernelFactory { public: @@ -343,13 +345,13 @@ class FaceBasedAssemblyKernelFactory elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - BitFlags< isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; if( hasCapPressure ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::CapPressure ); + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ); if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::FaceBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); - using KERNEL_TYPE = FaceBasedAssemblyKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using KERNEL_TYPE = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; typename KERNEL_TYPE::CompFlowAccessors compFlowAccessors( elemManager, solverName ); typename KERNEL_TYPE::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); typename KERNEL_TYPE::StabCompFlowAccessors stabCompFlowAccessors( elemManager, solverName ); @@ -372,4 +374,4 @@ class FaceBasedAssemblyKernelFactory } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDCOMPOSITIONALMULTIPHASEFVMKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STABILIZEDFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp new file mode 100644 index 00000000000..ae7c91fcc6e --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp @@ -0,0 +1,194 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StatisticsKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STATISTICSKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STATISTICSKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/relativePermeability/layouts.hpp" + + +namespace geos +{ + +namespace isothermalCompositionalMultiphaseBaseKernels +{ + +/******************************** StatisticsKernel ********************************/ + +struct StatisticsKernel +{ + template< typename POLICY > + static void + saveDeltaPressure( localIndex const size, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & initPres, + arrayView1d< real64 > const & deltaPres ) + { + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + deltaPres[ei] = pres[ei] - initPres[ei]; + } ); + } + + template< typename POLICY > + static void + launch( localIndex const size, + integer const numComps, + integer const numPhases, + real64 const relpermThreshold, + arrayView1d< integer const > const & elemGhostRank, + arrayView1d< real64 const > const & volume, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & deltaPres, + arrayView1d< real64 const > const & temp, + arrayView1d< real64 const > const & refPorosity, + arrayView2d< real64 const > const & porosity, + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDensity, + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const & phaseCompFraction, + arrayView2d< real64 const, compflow::USD_PHASE > const & phaseVolFrac, + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseTrappedVolFrac, + arrayView3d< real64 const, constitutive::relperm::USD_RELPERM > const & phaseRelperm, + real64 & minPres, + real64 & avgPresNumerator, + real64 & maxPres, + real64 & minDeltaPres, + real64 & maxDeltaPres, + real64 & minTemp, + real64 & avgTempNumerator, + real64 & maxTemp, + real64 & totalUncompactedPoreVol, + arrayView1d< real64 > const & phaseDynamicPoreVol, + arrayView1d< real64 > const & phaseMass, + arrayView1d< real64 > const & trappedPhaseMass, + arrayView1d< real64 > const & immobilePhaseMass, + arrayView2d< real64 > const & dissolvedComponentMass ) + { + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); + + // For this arrays phaseDynamicPoreVol, phaseMass, dissolvedComponentMass, + // using an array of ReduceSum leads to a formal parameter overflow in CUDA. + // As a workaround, we use a slice with RAJA::atomicAdd instead + + forAll< parallelDevicePolicy<> >( size, [numComps, + numPhases, + relpermThreshold, + elemGhostRank, + volume, + refPorosity, + porosity, + pres, + deltaPres, + temp, + phaseDensity, + phaseVolFrac, + phaseTrappedVolFrac, + phaseRelperm, + phaseCompFraction, + subRegionMinPres, + subRegionAvgPresNumerator, + subRegionMaxPres, + subRegionMinDeltaPres, + subRegionMaxDeltaPres, + subRegionMinTemp, + subRegionAvgTempNumerator, + subRegionMaxTemp, + subRegionTotalUncompactedPoreVol, + phaseDynamicPoreVol, + phaseMass, + trappedPhaseMass, + immobilePhaseMass, + dissolvedComponentMass] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( elemGhostRank[ei] >= 0 ) + { + return; + } + + // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages + real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; + real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; + + subRegionMinPres.min( pres[ei] ); + subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; + subRegionMaxPres.max( pres[ei] ); + + subRegionMaxDeltaPres.max( deltaPres[ei] ); + subRegionMinDeltaPres.min( deltaPres[ei] ); + + subRegionMinTemp.min( temp[ei] ); + subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; + subRegionMaxTemp.max( temp[ei] ); + subRegionTotalUncompactedPoreVol += uncompactedPoreVol; + for( integer ip = 0; ip < numPhases; ++ip ) + { + real64 const elemPhaseVolume = dynamicPoreVol * phaseVolFrac[ei][ip]; + real64 const elemPhaseMass = phaseDensity[ei][0][ip] * elemPhaseVolume; + real64 const elemTrappedPhaseMass = phaseDensity[ei][0][ip] * dynamicPoreVol * phaseTrappedVolFrac[ei][0][ip]; + // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) + RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseDynamicPoreVol[ip], elemPhaseVolume ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &phaseMass[ip], elemPhaseMass ); + RAJA::atomicAdd( parallelDeviceAtomic{}, &trappedPhaseMass[ip], elemTrappedPhaseMass ); + if( phaseRelperm[ei][0][ip] < relpermThreshold ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &immobilePhaseMass[ip], elemPhaseMass ); + } + for( integer ic = 0; ic < numComps; ++ic ) + { + // RAJA::atomicAdd used here because we do not use ReduceSum here (for the reason explained above) + RAJA::atomicAdd( parallelDeviceAtomic{}, &dissolvedComponentMass[ip][ic], phaseCompFraction[ei][0][ip][ic] * elemPhaseMass ); + } + } + + } ); + + minPres = subRegionMinPres.get(); + avgPresNumerator = subRegionAvgPresNumerator.get(); + maxPres = subRegionMaxPres.get(); + minDeltaPres = subRegionMinDeltaPres.get(); + maxDeltaPres = subRegionMaxDeltaPres.get(); + minTemp = subRegionMinTemp.get(); + avgTempNumerator = subRegionAvgTempNumerator.get(); + maxTemp = subRegionMaxTemp.get(); + totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); + + // dummy loop to bring data back to the CPU + forAll< serialPolicy >( 1, [phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass] ( localIndex const ) + { + GEOS_UNUSED_VAR( phaseDynamicPoreVol, phaseMass, trappedPhaseMass, immobilePhaseMass, dissolvedComponentMass ); + } ); + } +}; + +} // namespace isothermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_STATISTICSKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp new file mode 100644 index 00000000000..1dcaf7acbe4 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp @@ -0,0 +1,345 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalAccumulationKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALACCUMULATIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALACCUMULATIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @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 AccumulationKernel : public isothermalCompositionalMultiphaseBaseKernels::AccumulationKernel< NUM_COMP, NUM_DOF > +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::AccumulationKernel< NUM_COMP, NUM_DOF >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::m_numPhases; + using Base::m_rankOffset; + using Base::m_dofNumber; + using Base::m_elemGhostRank; + using Base::m_volume; + using Base::m_porosity; + using Base::m_dPoro_dPres; + using Base::m_dCompFrac_dCompDens; + using Base::m_phaseVolFrac; + using Base::m_dPhaseVolFrac; + using Base::m_phaseDens; + using Base::m_dPhaseDens; + using Base::m_phaseCompFrac; + using Base::m_dPhaseCompFrac; + using Base::m_localMatrix; + using Base::m_localRhs; + + /** + * @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 + */ + AccumulationKernel( localIndex const numPhases, + globalIndex const rankOffset, + string const dofKey, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags ) + : Base( numPhases, rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs, kernelFlags ), + m_dPoro_dTemp( solid.getDporosity_dTemperature() ), + m_phaseInternalEnergy( fluid.phaseInternalEnergy() ), + m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy() ), + m_rockInternalEnergy( solid.getInternalEnergy() ), + m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ), + m_energy_n( subRegion.getField< fields::flow::energy_n >() ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables() + : Base::StackVariables() + {} + + using Base::StackVariables::localRow; + using Base::StackVariables::dofIndices; + using Base::StackVariables::localResidual; + using Base::StackVariables::localJacobian; + + // derivative of pore volume wrt temperature + real64 dPoreVolume_dTemp = 0.0; + + // Solid energy + + /// Solid energy at time n+1 + real64 solidEnergy = 0.0; + + /// Derivative of solid internal energy with respect to pressure + real64 dSolidEnergy_dPres = 0.0; + + /// Derivative of solid internal energy with respect to temperature + real64 dSolidEnergy_dTemp = 0.0; + + }; + + /** + * @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 ); + + // derivative of pore volume wrt temperature + stack.dPoreVolume_dTemp = m_volume[ei] * m_dPoro_dTemp[ei][0]; + + // initialize the solid volume + real64 const solidVolume = m_volume[ei] * ( 1.0 - m_porosity[ei][0] ); + real64 const dSolidVolume_dPres = -m_volume[ei] * m_dPoro_dPres[ei][0]; + real64 const dSolidVolume_dTemp = -stack.dPoreVolume_dTemp; + + // initialize the solid internal energy + stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] + + dSolidVolume_dTemp * m_rockInternalEnergy[ei][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 + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // start with old time step value + stack.localResidual[numEqn-1] = -m_energy_n[ei]; + + Base::computeAccumulation( ei, stack, [&] ( integer const ip, + real64 const & phaseAmount, + 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, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0]; + arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0]; + arraySlice2d< real64 const, constitutive::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.dPoreVolume_dTemp * phaseVolFrac[ip] * phaseDens[ip] + + stack.poreVolume * (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 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; + + // 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; + } + } ); + + // Step 3: assemble the solid part of the accumulation term + + // local accumulation and derivatives w.r.t. pressure and temperature + stack.localResidual[numEqn-1] += stack.solidEnergy; + stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; + stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; + + } + + /** + * @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 = constitutive::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< serialAtomic >( stack.localRow + numEqn-1, + stack.dofIndices, + stack.localJacobian[numEqn-1], + numDof ); + } + +protected: + + /// View on derivative of porosity w.r.t temperature + arrayView2d< real64 const > const m_dPoro_dTemp; + + /// Views on phase internal energy + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_phaseInternalEnergy; + arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > m_dPhaseInternalEnergy; + + /// Views on rock internal energy + arrayView2d< real64 const > m_rockInternalEnergy; + arrayView2d< real64 const > m_dRockInternalEnergy_dTemp; + + /// Views on energy + arrayView1d< real64 const > m_energy_n; + +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +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[in] solid the solid 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, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + 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::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); + + AccumulationKernel< NUM_COMP, NUM_DOF > kernel( numPhases, rankOffset, dofKey, subRegion, + fluid, solid, localMatrix, localRhs, kernelFlags ); + AccumulationKernel< NUM_COMP, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALACCUMULATIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp new file mode 100644 index 00000000000..9dd607a5d0c --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp @@ -0,0 +1,352 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalDiffusionDispersionFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DiffusionDispersionFluxComputeKernel ********************************/ + +/** + * @class DiffusionDispersionFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of diffusion/dispersion flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class DiffusionDispersionFluxComputeKernel : + public isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using AbstractBase::m_dt; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dPhaseVolFrac; + + using Base = typename isothermalCompositionalMultiphaseFVMKernels::DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using DiffusionAccessors = typename Base::DiffusionAccessors; + using DispersionAccessors = typename Base::DispersionAccessors; + using PorosityAccessors = typename Base::PorosityAccessors; + using Base::numFluxSupportPoints; + using Base::numEqn; + using Base::numComp; + using Base::numDof; + using Base::m_referencePorosity; + using Base::m_phaseVolFrac; + using Base::m_phaseDens; + using Base::m_dPhaseDens; + using Base::m_phaseDiffusivityMultiplier; + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @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] diffusionAccessors + * @param[in] dispersionAccessors + * @param[in] porosityAccessors + * @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 + */ + DiffusionDispersionFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + DiffusionAccessors const & diffusionAccessors, + DispersionAccessors const & dispersionAccessors, + PorosityAccessors const & porosityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + diffusionAccessors, + dispersionAccessors, + porosityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::transmissibility; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + }; + + /** + * @brief Compute the local diffusion flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void computeDiffusionFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute the diffusionFlux and its derivatives (including derivatives wrt temperature), + // + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeDiffusionFlux( iconn, stack, [&] ( integer const ip, + integer const ic, + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const compFracGrad, + real64 const upwindCoefficient ) + { + // We are in the loop over phases and components, ip provides the current phase index. + + real64 dCompFracGrad_dT[numFluxSupportPoints]{}; + real64 dDiffusionFlux_dT[numFluxSupportPoints]{}; + + /// compute the TPFA component difference + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; + } + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dDiffusionFlux_dT[ke] += upwindCoefficient * dCompFracGrad_dT[ke]; + } + + // add contributions of the derivatives of upwind coefficient wrt temperature + real64 const dUpwindCoefficient_dT = + m_referencePorosity[er_up][esr_up][ei_up] * + m_phaseDiffusivityMultiplier[er_up][esr_up][ei_up][0][ip] * + ( m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * m_phaseVolFrac[er_up][esr_up][ei_up][ip] + + m_phaseDens[er_up][esr_up][ei_up][0][ip] * m_dPhaseVolFrac[er_up][esr_up][ei_up][ip][Deriv::dT] ); + dDiffusionFlux_dT[k_up] += dUpwindCoefficient_dT * compFracGrad; + + // finally, increment local flux and local Jacobian + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDiffusionFlux_dT[ke]; + stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDiffusionFlux_dT[ke]; + } + } ); + } + + /** + * @brief Compute the local dispersion flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void computeDispersionFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute the dispersionFlux and its derivatives (including derivatives wrt temperature), + // + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeDispersionFlux( iconn, stack, [&] ( integer const ip, + integer const ic, + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const compFracGrad ) + { + // We are in the loop over phases and components, ip provides the current phase index. + + real64 dCompFracGrad_dT[numFluxSupportPoints]{}; + real64 dDispersionFlux_dT[numFluxSupportPoints]{}; + + /// compute the TPFA component difference + for( integer i = 0; i < numFluxSupportPoints; i++ ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + dCompFracGrad_dT[i] += stack.transmissibility[connectionIndex][i] * m_dPhaseCompFrac[er][esr][ei][0][ip][ic][Deriv::dT]; + } + + // add contributions of the derivatives of component fractions wrt pressure/component fractions + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dDispersionFlux_dT[ke] += m_phaseDens[er_up][esr_up][ei_up][0][ip] * dCompFracGrad_dT[ke]; + } + + // add contributions of the derivatives of upwind coefficient wrt temperature + dDispersionFlux_dT[k_up] += m_dPhaseDens[er_up][esr_up][ei_up][0][ip][Deriv::dT] * compFracGrad; + + // finally, increment local flux and local Jacobian + integer const eqIndex0 = k[0] * numEqn + ic; + integer const eqIndex1 = k[1] * numEqn + ic; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const localDofIndexTemp = k[ke] * numDof + numComp + 1; + stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dDispersionFlux_dT[ke]; + stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dDispersionFlux_dT[ke]; + } + } ); + } +}; + +/** + * @class DiffusionDispersionFluxComputeKernelFactory + */ +class DiffusionDispersionFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @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 string to get the element degrees of freedom numbers + * @param[in] hasDiffusion flag specifying whether diffusion is used or not + * @param[in] hasDispersion flag specifying whether dispersion is used or not + * @param[in] solverName the name of the solver + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasDiffusion, + integer const hasDispersion, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + 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; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using kernelType = DiffusionDispersionFluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename kernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename kernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename kernelType::DiffusionAccessors diffusionAccessors( elemManager, solverName ); + typename kernelType::DispersionAccessors dispersionAccessors( elemManager, solverName ); + typename kernelType::PorosityAccessors porosityAccessors( elemManager, solverName ); + + kernelType kernel( numPhases, rankOffset, stencilWrapper, + dofNumberAccessor, compFlowAccessors, multiFluidAccessors, + diffusionAccessors, dispersionAccessors, porosityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + kernelType::template launch< POLICY >( stencilWrapper.size(), + hasDiffusion, hasDispersion, + kernel ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIFFUSIONDISPERSIONFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..edd4df9f192 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp @@ -0,0 +1,484 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalDirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp" +#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::DirichletFluxComputeKernel< NUM_COMP, + NUM_DOF, + FLUIDWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_numPhases; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_gravCoef; + using AbstractBase::m_phaseCompFrac; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dCompFrac_dCompDens; + + using Base = isothermalCompositionalMultiphaseFVMKernels::DirichletFluxComputeKernel< NUM_COMP, NUM_DOF, FLUIDWRAPPER >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::m_phaseMob; + using Base::m_dPhaseMob; + using Base::m_dPhaseMassDens; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + using Base::m_faceTemp; + using Base::m_faceGravCoef; + + + using ThermalCompFlowAccessors = + StencilAccessors< fields::flow::temperature >; + + using ThermalMultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseEnthalpy, + fields::multifluid::dPhaseEnthalpy >; + + using ThermalConductivityAccessors = + StencilMaterialAccessors< constitutive::MultiPhaseThermalConductivityBase, + fields::thermalconductivity::effectiveConductivity >; + // for now, we treat thermal conductivity explicitly + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] compFlowAccessor accessor for wrappers registered by the solver + * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver + * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model + * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model + * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model + * @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 + */ + DirichletFluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + ThermalCompFlowAccessors const & thermalCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), + m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) + {} + + struct StackVariables : public Base::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, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::transmissibility; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + // Component fluxes and derivatives + + /// Derivatives of component fluxes wrt temperature + real64 dCompFlux_dT[numComp]{}; + + + // Energy fluxes and derivatives + + /// Energy fluxes + real64 energyFlux = 0.0; + /// Derivative of energy fluxes wrt pressure + real64 dEnergyFlux_dP = 0.0; + /// Derivative of energy fluxes wrt temperature + real64 dEnergyFlux_dT = 0.0; + /// Derivatives of energy fluxes wrt component densities + real64 dEnergyFlux_dC[numComp]{}; + + }; + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Order = BoundaryStencil::Order; + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute: + // 1) compFlux and its derivatives (including derivatives wrt temperature), + // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature) + // + // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, + // such as potGrad, phaseFlux, and the indices of the upwind cell + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeFlux( iconn, stack, [&] ( integer const ip, + localIndex const er, + localIndex const esr, + localIndex const ei, + localIndex const kf, + real64 const f, // potGrad times trans + real64 const facePhaseMob, + arraySlice1d< const real64, constitutive::multifluid::USD_PHASE - 2 > const & facePhaseEnthalpy, + arraySlice2d< const real64, constitutive::multifluid::USD_PHASE_COMP-2 > const & facePhaseCompFrac, + real64 const phaseFlux, + real64 const dPhaseFlux_dP, + real64 const (&dPhaseFlux_dC)[numComp] ) + { + // We are in the loop over phases, ip provides the current phase index. + + // Step 1: compute the derivatives of the mean density at the interface wrt temperature + + real64 const dDensMean_dT = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; + + // Step 2: compute the derivatives of the phase potential difference wrt temperature + //***** calculation of flux ***** + + real64 const dF_dT = -stack.transmissibility * dDensMean_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); + + // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature + // *** upwinding *** + + // note: the upwinding is done in the base class, which is in charge of + // computing the following quantities: potGrad, phaseFlux + // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way + + + if( f >= 0 ) // the element is upstream + { + + // Step 3.1.a: compute the derivative of phase flux wrt temperature + real64 const dPhaseFlux_dT = m_phaseMob[er][esr][ei][ip] * dF_dT + m_dPhaseMob[er][esr][ei][ip][Deriv::dT] * f; + + // Step 3.2.a: compute the derivative of component flux wrt temperature + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = + m_phaseCompFrac[er][esr][ei][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = + m_dPhaseCompFrac[er][esr][ei][0][ip]; + + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; + } + + // Step 3.3.a: compute the enthalpy flux + + real64 const enthalpy = m_phaseEnthalpy[er][esr][ei][0][ip]; + stack.energyFlux += phaseFlux * enthalpy; + stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP]; + stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT]; + + real64 dProp_dC[numComp]{}; + applyChainRule( numComp, + m_dCompFrac_dCompDens[er][esr][ei], + m_dPhaseEnthalpy[er][esr][ei][0][ip], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy + phaseFlux * dProp_dC[jc]; + } + + } + else // the face is upstream + { + + // Step 3.1.b: compute the derivative of phase flux wrt temperature + real64 const dPhaseFlux_dT = facePhaseMob * dF_dT; + + // Step 3.2.b: compute the derivative of component flux wrt temperature + + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = facePhaseCompFrac[ip][ic]; + stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp; + } + + // Step 3.3.b: compute the enthalpy flux + + real64 const enthalpy = facePhaseEnthalpy[ip]; + stack.energyFlux += phaseFlux * enthalpy; + stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy; + stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy; + } + + } + + } ); + + // ***************************************************** + // Computation of the conduction term in the energy flux + // Note that the phase enthalpy term in the energy was computed above + // Note that this term is computed using an explicit treatment of conductivity for now + + // Step 1: compute the thermal transmissibilities at this face + // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity + // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice + // TODO: modify computeWeights to accomodate explicit coefficients + real64 thermalTrans = 0.0; + real64 dThermalTrans_dPerm[3]{}; // not used + m_stencilWrapper.computeWeights( iconn, + m_thermalConductivity, + thermalTrans, + dThermalTrans_dPerm ); + + // Step 2: compute temperature difference at the interface + stack.energyFlux += thermalTrans + * ( m_temp[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] - m_faceTemp[m_sei( iconn, Order::FACE )] ); + stack.dEnergyFlux_dT += thermalTrans; + + + // ********************************************************************************** + // At this point, we have computed the energyFlux and the compFlux for all components + // We have to do two things here: + // 1) Add dCompFlux_dTemp to the localFluxJacobian of the component mass balance equations + // 2) Add energyFlux and its derivatives to the localFlux(Jacobian) of the energy balance equation + + // Step 1: add dCompFlux_dTemp to localFluxJacobian + for( integer ic = 0; ic < numComp; ++ic ) + { + stack.localFluxJacobian[ic][numDof-1] = m_dt * stack.dCompFlux_dT[ic]; + } + + // Step 2: add energyFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy = numEqn-1; + stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; + + stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; + stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; + for( integer jc = 0; jc < numComp; ++jc ) + { + stack.localFluxJacobian[localRowIndexEnergy][jc+1] = m_dt * stack.dEnergyFlux_dC[jc]; + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack ) const + { + // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) + // In the lambda, add contribution to residual and jacobian into the energy balance equation + Base::complete( iconn, stack, [&] ( localIndex const localRow ) + { + // beware, there is volume balance eqn in m_localRhs and m_localMatrix! + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[numEqn-1] ); + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + numEqn, + stack.dofColIndices, + stack.localFluxJacobian[numEqn-1], + numDof ); + + } ); + } + +protected: + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on phase enthalpies + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; + + /// View on thermal conductivity + ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; + // for now, we treat thermal conductivity explicitly + +}; + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @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 string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidBase the multifluid constitutive model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + integer const useTotalMassEquation, + string const & dofKey, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + constitutive::MultiFluidBase & fluidBase, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutive::constitutiveComponentUpdatePassThru< true >( fluidBase, numComps, [&]( auto & fluid, auto NC ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_COMP = NC(); + integer constexpr NUM_DOF = NC() + 2; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + // for now, we neglect capillary pressure in the kernel + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using KernelType = DirichletFluxComputeKernel< NUM_COMP, NUM_DOF, typename FluidType::KernelWrapper >; + typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); + typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); + typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); + + KernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper, + dofNumberAccessor, compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, + capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp new file mode 100644 index 00000000000..17395f62324 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp @@ -0,0 +1,572 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/fluid/multifluid/MultiFluidFields.hpp" +#include "constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp" +#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** FluxComputeKernel ********************************/ + +/** + * @class FluxComputeKernel + * @tparam NUM_COMP number of fluid components + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_COMP, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER > +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using CompFlowAccessors = AbstractBase::CompFlowAccessors; + using MultiFluidAccessors = AbstractBase::MultiFluidAccessors; + using CapPressureAccessors = AbstractBase::CapPressureAccessors; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_numPhases; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_gravCoef; + using AbstractBase::m_phaseVolFrac; + using AbstractBase::m_dPhaseVolFrac; + using AbstractBase::m_phaseCompFrac; + using AbstractBase::m_dPhaseCompFrac; + using AbstractBase::m_dCompFrac_dCompDens; + + using Base = isothermalCompositionalMultiphaseFVMKernels::FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + using Base::numComp; + using Base::numDof; + using Base::numEqn; + using Base::maxNumElems; + using Base::maxNumConns; + using Base::maxStencilSize; + using Base::numFluxSupportPoints; + using Base::m_phaseMob; + using Base::m_dPhaseMob; + using Base::m_dPhaseMassDens; + using Base::m_dPhaseCapPressure_dPhaseVolFrac; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + using ThermalCompFlowAccessors = + StencilAccessors< fields::flow::temperature >; + + using ThermalMultiFluidAccessors = + StencilMaterialAccessors< constitutive::MultiFluidBase, + fields::multifluid::phaseEnthalpy, + fields::multifluid::dPhaseEnthalpy >; + + using ThermalConductivityAccessors = + StencilMaterialAccessors< constitutive::MultiPhaseThermalConductivityBase, + fields::thermalconductivity::effectiveConductivity >; + // for now, we treat thermal conductivity explicitly + + /** + * @brief Constructor for the kernel interface + * @param[in] numPhases the number of fluid phases + * @param[in] rankOffset the offset of my MPI rank + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dofNumberAccessor accessor for the dofs numbers + * @param[in] compFlowAccessor accessor for wrappers registered by the solver + * @param[in] thermalCompFlowAccessors accessor for *thermal* wrappers registered by the solver + * @param[in] multiFluidAccessor accessor for wrappers registered by the multifluid model + * @param[in] thermalMultiFluidAccessors accessor for *thermal* wrappers registered by the multifluid model + * @param[in] capPressureAccessors accessor for wrappers registered by the cap pressure model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] thermalConductivityAccessors accessor for wrappers registered by the thermal conductivity model + * @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 all together + */ + FluxComputeKernel( integer const numPhases, + globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + CompFlowAccessors const & compFlowAccessors, + ThermalCompFlowAccessors const & thermalCompFlowAccessors, + MultiFluidAccessors const & multiFluidAccessors, + ThermalMultiFluidAccessors const & thermalMultiFluidAccessors, + CapPressureAccessors const & capPressureAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs, + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags ) + : Base( numPhases, + rankOffset, + stencilWrapper, + dofNumberAccessor, + compFlowAccessors, + multiFluidAccessors, + capPressureAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs, + kernelFlags ), + m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ), + m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ), + m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ), + m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ) + {} + + struct StackVariables : public Base::StackVariables + { +public: + + GEOS_HOST_DEVICE + StackVariables( localIndex const size, localIndex numElems ) + : Base::StackVariables( size, numElems ) + {} + + using Base::StackVariables::stencilSize; + using Base::StackVariables::numConnectedElems; + using Base::StackVariables::transmissibility; + using Base::StackVariables::dTrans_dPres; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + + // Thermal transmissibility (for now, no derivatives) + + real64 thermalTransmissibility[maxNumConns][2]{}; + }; + + /** + * @brief Compute the local flux contributions to the residual and Jacobian + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + // *********************************************** + // First, we call the base computeFlux to compute: + // 1) compFlux and its derivatives (including derivatives wrt temperature), + // 2) enthalpy part of convectiveEnergyFlux and its derivatives (including derivatives wrt temperature) + // + // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux, + // such as potGrad, phaseFlux, and the indices of the upwind cell + // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables + Base::computeFlux( iconn, stack, [&] ( integer const ip, + localIndex const (&k)[2], + localIndex const (&seri)[2], + localIndex const (&sesri)[2], + localIndex const (&sei)[2], + localIndex const connectionIndex, + localIndex const k_up, + localIndex const er_up, + localIndex const esr_up, + localIndex const ei_up, + real64 const potGrad, + real64 const phaseFlux, + real64 const (&dPhaseFlux_dP)[2], + real64 const (&dPhaseFlux_dC)[2][numComp] ) + { + // We are in the loop over phases, ip provides the current phase index. + + // Step 1: compute the derivatives of the mean density at the interface wrt temperature + + real64 dDensMean_dT[numFluxSupportPoints]{}; + + real64 const trans[numFluxSupportPoints] = { stack.transmissibility[connectionIndex][0], + stack.transmissibility[connectionIndex][1] }; + + real64 convectiveEnergyFlux = 0.0; + real64 dConvectiveEnergyFlux_dP[numFluxSupportPoints]{}; + real64 dConvectiveEnergyFlux_dT[numFluxSupportPoints]{}; + real64 dConvectiveEnergyFlux_dC[numFluxSupportPoints][numComp]{}; + real64 dCompFlux_dT[numFluxSupportPoints][numComp]{}; + + integer denom = 0; + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + bool const phaseExists = (m_phaseVolFrac[er_up][esr_up][ei_up][ip] > 0); + if( !phaseExists ) + { + continue; + } + + dDensMean_dT[i] = m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT]; + denom++; + } + if( denom > 1 ) + { + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + dDensMean_dT[i] /= denom; + } + } + + // Step 2: compute the derivatives of the phase potential difference wrt temperature + //***** calculation of flux ***** + + real64 dPresGrad_dT[numFluxSupportPoints]{}; + real64 dGravHead_dT[numFluxSupportPoints]{}; + + // compute potential difference MPFA-style + for( integer i = 0; i < numFluxSupportPoints; ++i ) + { + localIndex const er = seri[i]; + localIndex const esr = sesri[i]; + localIndex const ei = sei[i]; + + // Step 2.1: compute derivative of capillary pressure wrt temperature + real64 dCapPressure_dT = 0.0; + if( AbstractBase::m_kernelFlags.isSet( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ) ) + { + for( integer jp = 0; jp < m_numPhases; ++jp ) + { + real64 const dCapPressure_dS = m_dPhaseCapPressure_dPhaseVolFrac[er][esr][ei][0][ip][jp]; + dCapPressure_dT += dCapPressure_dS * m_dPhaseVolFrac[er][esr][ei][jp][Deriv::dT]; + } + } + + // Step 2.2: compute derivative of phase pressure difference wrt temperature + dPresGrad_dT[i] -= trans[i] * dCapPressure_dT; + real64 const gravD = trans[i] * m_gravCoef[er][esr][ei]; + + // Step 2.3: compute derivative of gravity potential difference wrt temperature + for( integer j = 0; j < numFluxSupportPoints; ++j ) + { + dGravHead_dT[j] += dDensMean_dT[j] * gravD; + } + } + + // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature + // *** upwinding *** + + // note: the upwinding is done in the base class, which is in charge of + // computing the following quantities: potGrad, phaseFlux, k_up, er_up, esr_up, ei_up + + real64 dPhaseFlux_dT[numFluxSupportPoints]{}; + + // Step 3.1: compute the derivative of phase flux wrt temperature + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dT[ke] += dPresGrad_dT[ke]; + } + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dT[ke] -= dGravHead_dT[ke]; + } + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dPhaseFlux_dT[ke] *= m_phaseMob[er_up][esr_up][ei_up][ip]; + } + dPhaseFlux_dT[k_up] += m_dPhaseMob[er_up][esr_up][ei_up][ip][Deriv::dT] * potGrad; + + // Step 3.2: compute the derivative of component flux wrt temperature + + // slice some constitutive arrays to avoid too much indexing in component loop + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub = + m_phaseCompFrac[er_up][esr_up][ei_up][0][ip]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub = + m_dPhaseCompFrac[er_up][esr_up][ei_up][0][ip]; + + for( integer ic = 0; ic < numComp; ++ic ) + { + real64 const ycp = phaseCompFracSub[ic]; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dCompFlux_dT[ke][ic] += dPhaseFlux_dT[ke] * ycp; + } + dCompFlux_dT[k_up][ic] += phaseFlux * dPhaseCompFracSub[ic][Deriv::dT]; + } + + // Step 4: add dCompFlux_dTemp to localFluxJacobian + for( integer ic = 0; ic < numComp; ++ic ) + { + integer const eqIndex0 = k[0]* numEqn + ic; + integer const eqIndex1 = k[1]* numEqn + ic; + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; + stack.localFluxJacobian[eqIndex0][localDofIndexTemp] += m_dt * dCompFlux_dT[ke][ic]; + stack.localFluxJacobian[eqIndex1][localDofIndexTemp] -= m_dt * dCompFlux_dT[ke][ic]; + } + } + + // Step 5: compute the enthalpy flux + real64 const enthalpy = m_phaseEnthalpy[er_up][esr_up][ei_up][0][ip]; + convectiveEnergyFlux += phaseFlux * enthalpy; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + dConvectiveEnergyFlux_dP[ke] += dPhaseFlux_dP[ke] * enthalpy; + dConvectiveEnergyFlux_dT[ke] += dPhaseFlux_dT[ke] * enthalpy; + + for( integer jc = 0; jc < numComp; ++jc ) + { + dConvectiveEnergyFlux_dC[ke][jc] += dPhaseFlux_dC[ke][jc] * enthalpy; + } + } + + dConvectiveEnergyFlux_dP[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dP]; + dConvectiveEnergyFlux_dT[k_up] += phaseFlux * m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip][Deriv::dT]; + + real64 dProp_dC[numComp]{}; + applyChainRule( numComp, + m_dCompFrac_dCompDens[er_up][esr_up][ei_up], + m_dPhaseEnthalpy[er_up][esr_up][ei_up][0][ip], + dProp_dC, + Deriv::dC ); + for( integer jc = 0; jc < numComp; ++jc ) + { + dConvectiveEnergyFlux_dC[k_up][jc] += phaseFlux * dProp_dC[jc]; + } + + // Step 6: add convectiveFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; + integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; + stack.localFlux[localRowIndexEnergy0] += m_dt * convectiveEnergyFlux; + stack.localFlux[localRowIndexEnergy1] -= m_dt * convectiveEnergyFlux; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + integer const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexPres] += m_dt * dConvectiveEnergyFlux_dP[ke]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexPres] -= m_dt * dConvectiveEnergyFlux_dP[ke]; + integer const localDofIndexTemp = localDofIndexPres + numDof - 1; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConvectiveEnergyFlux_dT[ke]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConvectiveEnergyFlux_dT[ke]; + + for( integer jc = 0; jc < numComp; ++jc ) + { + integer const localDofIndexComp = localDofIndexPres + jc + 1; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexComp] += m_dt * dConvectiveEnergyFlux_dC[ke][jc]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexComp] -= m_dt * dConvectiveEnergyFlux_dC[ke][jc]; + } + } + } ); + + // ***************************************************** + // Computation of the conduction term in the energy flux + // Note that the phase enthalpy term in the energy was computed above + // Note that this term is computed using an explicit treatment of conductivity for now + + // Step 1: compute the thermal transmissibilities at this face + // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity + // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice + // TODO: modify computeWeights to accomodate explicit coefficients + m_stencilWrapper.computeWeights( iconn, + m_thermalConductivity, + m_thermalConductivity, // we have to pass something here, so we just use thermal conductivity + stack.thermalTransmissibility, + stack.dTrans_dPres ); // again, we have to pass something here, but this is unused for now + + + + localIndex k[2]{}; + localIndex connectionIndex = 0; + + for( k[0] = 0; k[0] < stack.numConnectedElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numConnectedElems; ++k[1] ) + { + real64 const thermalTrans[2] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] }; + localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + real64 conductiveEnergyFlux = 0.0; + real64 dConductiveEnergyFlux_dT[numFluxSupportPoints]{}; + + // Step 2: compute temperature difference at the interface + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + localIndex const er = seri[ke]; + localIndex const esr = sesri[ke]; + localIndex const ei = sei[ke]; + + conductiveEnergyFlux += thermalTrans[ke] * m_temp[er][esr][ei]; + dConductiveEnergyFlux_dT[ke] += thermalTrans[ke]; + } + + // Step 3: add conductiveFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy0 = k[0] * numEqn + numEqn - 1; + integer const localRowIndexEnergy1 = k[1] * numEqn + numEqn - 1; + stack.localFlux[localRowIndexEnergy0] += m_dt * conductiveEnergyFlux; + stack.localFlux[localRowIndexEnergy1] -= m_dt * conductiveEnergyFlux; + + for( integer ke = 0; ke < numFluxSupportPoints; ++ke ) + { + integer const localDofIndexTemp = k[ke] * numDof + numDof - 1; + stack.localFluxJacobian[localRowIndexEnergy0][localDofIndexTemp] += m_dt * dConductiveEnergyFlux_dT[ke]; + stack.localFluxJacobian[localRowIndexEnergy1][localDofIndexTemp] -= m_dt * dConductiveEnergyFlux_dT[ke]; + } + } + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + inline + void complete( localIndex const iconn, + StackVariables & stack ) const + { + // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2) + // In the lambda, add contribution to residual and jacobian into the energy balance equation + Base::complete( iconn, stack, [&] ( integer const i, + localIndex const localRow ) + { + // beware, there is volume balance eqn in m_localRhs and m_localMatrix! + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[i * numEqn + numEqn-1] ); + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + numEqn, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn + numEqn-1].dataIfContiguous(), + stack.stencilSize * numDof ); + + } ); + } + +protected: + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on phase enthalpies + ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseEnthalpy; + ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > > const m_dPhaseEnthalpy; + + /// View on thermal conductivity + ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity; + // for now, we treat thermal conductivity explicitly + +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @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 string to get the element degrees of freedom numbers + * @param[in] hasCapPressure flag specifying whether capillary pressure is used or not + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + integer const hasCapPressure, + integer const useTotalMassEquation, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const dt, + 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; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags; + if( hasCapPressure ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::CapPressure ); + if( useTotalMassEquation ) + kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation ); + + using KernelType = FluxComputeKernel< NUM_COMP, NUM_DOF, STENCILWRAPPER >; + typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName ); + typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName ); + typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName ); + typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName ); + typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName ); + typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); + + KernelType kernel( numPhases, rankOffset, stencilWrapper, dofNumberAccessor, + compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors, + capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors, + dt, localMatrix, localRhs, kernelFlags ); + KernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp new file mode 100644 index 00000000000..f6be6b2cf55 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp @@ -0,0 +1,154 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalPhaseMobilityKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEMOBILITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEMOBILITYKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseFVMKernels +{ + +/******************************** PhaseMobilityKernel ********************************/ + +/** + * @class PhaseMobilityKernel + * @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 phase mobilities + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseMobilityKernel : public isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE > +{ +public: + + using Base = isothermalCompositionalMultiphaseFVMKernels::PhaseMobilityKernel< NUM_COMP, NUM_PHASE >; + using Base::numPhase; + using Base::m_dPhaseVolFrac; + using Base::m_dPhaseMob; + using Base::m_phaseDens; + using Base::m_dPhaseDens; + using Base::m_phaseVisc; + using Base::m_dPhaseVisc; + using Base::m_dPhaseRelPerm_dPhaseVolFrac; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] relperm the relperm model + */ + PhaseMobilityKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + : Base( subRegion, fluid, relperm ) + {} + + /** + * @brief Compute the phase mobilities in an element + * @param[in] ei the element index + */ + GEOS_HOST_DEVICE + inline + void compute( localIndex const ei ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseDens = m_phaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > const phaseVisc = m_phaseVisc[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseVisc = m_dPhaseVisc[ei][0]; + arraySlice2d< real64 const, constitutive::relperm::USD_RELPERM_DS - 2 > const dPhaseRelPerm_dPhaseVolFrac = m_dPhaseRelPerm_dPhaseVolFrac[ei][0]; + arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + Base::compute( ei, [&] ( localIndex const ip, + real64 const & phaseMob, + arraySlice1d< real64, compflow::USD_PHASE_DC - 2 > const & dPhaseMob ) + { + // Step 1: compute the derivative of relPerm[ip] wrt temperature + real64 dRelPerm_dT = 0.0; + for( integer jp = 0; jp < numPhase; ++jp ) + { + dRelPerm_dT += dPhaseRelPerm_dPhaseVolFrac[ip][jp] * dPhaseVolFrac[jp][Deriv::dT]; + } + + // Step 2: compute the derivative of phaseMob[ip] wrt temperature + dPhaseMob[Deriv::dT] = dRelPerm_dT * phaseDens[ip] / phaseVisc[ip] + + phaseMob * (dPhaseDens[ip][Deriv::dT] / phaseDens[ip] - dPhaseVisc[ip][Deriv::dT] / phaseVisc[ip] ); + } ); + } + +}; + +/** + * @class PhaseMobilityKernelFactory + */ +class PhaseMobilityKernelFactory +{ +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 + * @param[in] relperm the relperm model + */ + template< typename POLICY > + static void + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::RelativePermeabilityBase const & relperm ) + { + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 2 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseMobilityKernel< NUM_COMP, 3 > kernel( subRegion, fluid, relperm ); + PhaseMobilityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + } +}; + +} // namespace thermalCompositionalMultiphaseFVMKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEMOBILITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp new file mode 100644 index 00000000000..375fecd1cea --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp @@ -0,0 +1,140 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalPhaseVolumeFractionKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEVOLUMEFRACTIONKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEVOLUMEFRACTIONKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** PhaseVolumeFractionKernel ********************************/ + +/** + * @class PhaseVolumeFractionKernel + * @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 phase volume fractions + */ +template< integer NUM_COMP, integer NUM_PHASE > +class PhaseVolumeFractionKernel : public isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE > +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::PhaseVolumeFractionKernel< NUM_COMP, NUM_PHASE >; + using Base::m_dPhaseDens; + using Base::m_dPhaseFrac; + using Base::m_dPhaseVolFrac; + + /** + * @brief Constructor + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + */ + PhaseVolumeFractionKernel( ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + : Base( subRegion, fluid ) + {} + + /** + * @brief Compute the phase volume fractions in an element + * @param[in] ei the element index + */ + GEOS_HOST_DEVICE + real64 compute( localIndex const ei ) const + { + using Deriv = constitutive::multifluid::DerivativeOffset; + + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseDens = m_dPhaseDens[ei][0]; + arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > const dPhaseFrac = m_dPhaseFrac[ei][0]; + + arraySlice2d< real64, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dPhaseVolFrac[ei]; + + // Call the base compute the compute the phase volume fraction + return Base::compute( ei, [&] ( localIndex const ip, + real64 const & phaseVolFrac, + real64 const & phaseDensInv, + real64 const & totalDensity ) + { + // when this lambda is called, we are in the phase loop + // for each phase ip, compute the derivative of phase volume fraction wrt temperature + dPhaseVolFrac[ip][Deriv::dT] = (dPhaseFrac[ip][Deriv::dT] - phaseVolFrac * dPhaseDens[ip][Deriv::dT]) * phaseDensInv; + dPhaseVolFrac[ip][Deriv::dT] *= totalDensity; + } ); + } + +}; + +/** + * @class PhaseVolumeFractionKernelFactory + */ +class PhaseVolumeFractionKernelFactory +{ +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 real64 + createAndLaunch( integer const numComp, + integer const numPhase, + ObjectManagerBase & subRegion, + constitutive::MultiFluidBase const & fluid ) + { + real64 maxDeltaPhaseVolFrac = 0.0; + if( numPhase == 2 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 2 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + else if( numPhase == 3 ) + { + isothermalCompositionalMultiphaseBaseKernels:: + internal::kernelLaunchSelectorCompSwitch( numComp, [&] ( auto NC ) + { + integer constexpr NUM_COMP = NC(); + PhaseVolumeFractionKernel< NUM_COMP, 3 > kernel( subRegion, fluid ); + maxDeltaPhaseVolFrac = PhaseVolumeFractionKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel ); + } ); + } + return maxDeltaPhaseVolFrac; + } +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALPHASEVOLUMEFRACTIONKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp new file mode 100644 index 00000000000..7dbb7bab2f9 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp @@ -0,0 +1,241 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalResidualNormKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALRESIDUALNORMKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALRESIDUALNORMKERNEL_HPP + +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class ResidualNormKernel + */ +class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 3 > +{ +public: + + using Base = ResidualNormKernelBase< 3 >; + 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 numComponents, + integer const numPhases, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + constitutive::SolidInternalEnergy const & solidInternalEnergy, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_numComponents( numComponents ), + m_numPhases( numPhases ), + m_volume( subRegion.getElementVolume() ), + m_porosity_n( solid.getPorosity_n() ), + m_phaseVolFrac_n( subRegion.getField< fields::flow::phaseVolumeFraction_n >() ), + m_totalDens_n( fluid.totalDensity_n() ), + m_phaseDens_n( fluid.phaseDensity_n() ), + m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() ), + m_solidInternalEnergy_n( solidInternalEnergy.getInternalEnergy_n() ) + {} + + GEOS_HOST_DEVICE + void computeMassEnergyNormalizers( localIndex const ei, + real64 & massNormalizer, + real64 & energyNormalizer ) const + { + massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[ei][0] * m_porosity_n[ei][0] * m_volume[ei] ); + real64 const poreVolume = m_porosity_n[ei][0] * m_volume[ei]; + energyNormalizer = m_solidInternalEnergy_n[ei][0] * ( 1.0 - m_porosity_n[ei][0] ) * m_volume[ei]; + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + energyNormalizer += m_phaseInternalEnergy_n[ei][0][ip] * m_phaseDens_n[ei][0][ip] * m_phaseVolFrac_n[ei][ip] * poreVolume; + } + // warning: internal energy can be negative + energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( energyNormalizer ) ); + } + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + real64 const volumeNormalizer = LvArray::math::max( m_minNormalizer, m_porosity_n[ei][0] * m_volume[ei] ); + + // step 1: mass residual + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + } + + // step 2: volume residual + + real64 const valVol = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents] ) / volumeNormalizer; + if( valVol > stack.localValue[1] ) + { + stack.localValue[1] = valVol; + } + + // step 3: energy residual + + real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + m_numComponents + 1] ) / energyNormalizer; + if( valEnergy > stack.localValue[2] ) + { + stack.localValue[2] = valEnergy; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + // note: for the L2 norm, we bundle the volume and mass residuals/normalizers + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + + // step 1: mass residual + + for( integer idof = 0; idof < m_numComponents; ++idof ) + { + stack.localValue[0] += m_localResidual[stack.localRow + idof] * m_localResidual[stack.localRow + idof]; + stack.localNormalizer[0] += massNormalizer; + } + + // step 2: volume residual + + real64 const valVol = m_localResidual[stack.localRow + m_numComponents] * m_totalDens_n[ei][0]; // we need a mass here, hence the + // multiplication + stack.localValue[1] += valVol * valVol; + stack.localNormalizer[1] += massNormalizer; + + // step 3: energy residual + + stack.localValue[2] += m_localResidual[stack.localRow + m_numComponents + 1] * m_localResidual[stack.localRow + m_numComponents + 1]; + stack.localNormalizer[2] += energyNormalizer; + } + +protected: + + /// Number of fluid components + integer const m_numComponents; + + /// Number of fluid phases + integer const m_numPhases; + + /// View on the volume + arrayView1d< real64 const > const m_volume; + + /// View on porosity at the previous converged time step + arrayView2d< real64 const > const m_porosity_n; + + /// View on phase properties at the previous converged time step + arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac_n; + arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const m_totalDens_n; + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens_n; + arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseInternalEnergy_n; + + /// View on solid properties at the previous converged time step + arrayView2d< real64 const > const m_solidInternalEnergy_n; + +}; + +/** + * @class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @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] localResidual the residual vector on my MPI rank + * @param[in] subRegion the element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[in] solidInternalEnergy the solid internal energy model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + integer const numComps, + integer const numPhases, + globalIndex const rankOffset, + string const & dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + constitutive::MultiFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + constitutive::SolidInternalEnergy const & solidInternalEnergy, + real64 const minNormalizer, + real64 (& residualNorm)[3], + real64 (& residualNormalizer)[3] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, + numComps, numPhases, subRegion, fluid, solid, solidInternalEnergy, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + ResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + + } +}; + + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALRESIDUALNORMKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp new file mode 100644 index 00000000000..57007c9f673 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp @@ -0,0 +1,181 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalSolutionCheckKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONCHECKKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONCHECKKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionCheckKernel ********************************/ + +/** + * @class SolutionCheckKernel + * @brief Define the kernel for checking the updated solution + */ +class SolutionCheckKernel : public isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::SolutionCheckKernel; + using Base::m_numComp; + using Base::m_localSolution; + using Base::m_scalingFactor; + + static real64 constexpr minTemperature = constants::zeroDegreesCelsiusInKelvin; + + /** + * @brief Create a new kernel instance + * @param[in] allowCompDensChopping flag to allow the component density chopping + * @param[in] scalingFactor the scaling factor + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] temperature the temperature vector + * @param[in] compDens the component density vector + */ + SolutionCheckKernel( integer const allowCompDensChopping, + 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 > compDensScalingFactor, + 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 ), + m_temperature( temperature ), + m_temperatureScalingFactor( temperatureScalingFactor ), + m_temperatureOffset( temperatureOffset ) + {} + + /** + * @brief Compute the local value of the solution check + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeSolutionCheck( localIndex const ei, + StackVariables & stack ) const + { + Base::computeSolutionCheck( ei, stack, [&] () + { + 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_temperatureOffset]); + if( newTemp < minTemperature ) + { + stack.localMinVal = 0; + } + } ); + } + +protected: + + /// View on the primary variables + arrayView1d< real64 const > const m_temperature; + + /// View on the scaling factor + arrayView1d< real64 const > const m_temperatureScalingFactor; + + /// Offset to temperature variable + integer m_temperatureOffset; + +}; + +/** + * @class SolutionCheckKernelFactory + */ +class SolutionCheckKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxRelativeTempChange the max allowed relative temperature change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static SolutionCheckKernel::StackVariables + createAndLaunch( integer const allowCompDensChopping, + 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, + integer temperatureOffset ) + { + SolutionCheckKernel kernel( allowCompDensChopping, allowNegativePressure, scalingType, scalingFactor, + pressure, temperature, compDens, pressureScalingFactor, compDensScalingFactor, temperatureScalingFactor, + rankOffset, numComp, dofKey, subRegion, localSolution, + temperatureOffset ); + return SolutionCheckKernel::launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONCHECKKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp new file mode 100644 index 00000000000..00af7a5eca4 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp @@ -0,0 +1,226 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalSolutionScalingKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONSCALINGKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONSCALINGKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" + +namespace geos +{ + +namespace thermalCompositionalMultiphaseBaseKernels +{ + +/******************************** SolutionScalingKernel ********************************/ + +/** + * @class SolutionScalingKernel + * @brief Define the kernel for scaling the Newton update + */ +class SolutionScalingKernel : public isothermalCompositionalMultiphaseBaseKernels::SolutionScalingKernel +{ +public: + + using Base = isothermalCompositionalMultiphaseBaseKernels::SolutionScalingKernel; + using Base::m_numComp; + using Base::m_localSolution; + + /** + * @brief Create a new kernel instance + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxRelativeTempChange the max allowed relative temperature change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompDensChange the max allowed comp density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + * @param[in] pressure the pressure vector + * @param[in] temperature the temperature vector + * @param[in] compDens the component density vector + * @param[in] pressureScalingFactor the pressure local scaling factor + * @param[in] compDensScalingFactor the component density local scaling factor + * @param[in] temperatureFactor the temperature local scaling factor + */ + SolutionScalingKernel( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxRelativeTempChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + 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, + integer const temperatureOffset ) + : Base( maxRelativePresChange, + maxAbsolutePresChange, + maxCompFracChange, + maxRelativeCompDensChange, + rankOffset, + numComp, + dofKey, + subRegion, + localSolution, + pressure, + compDens, + pressureScalingFactor, + compDensScalingFactor ), + m_maxRelativeTempChange( maxRelativeTempChange ), + m_temperature( temperature ), + m_temperatureScalingFactor( temperatureScalingFactor ), + m_temperatureOffset( temperatureOffset ) + {} + + /** + * @brief Compute the local value + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void compute( localIndex const ei, + StackVariables & stack ) const + { + computeScalingFactor( ei, stack ); + } + + /** + * @brief Compute the local value of the scaling factor + * @param[in] ei the element index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void computeScalingFactor( localIndex const ei, + StackVariables & stack ) const + { + real64 constexpr eps = isothermalCompositionalMultiphaseBaseKernels::minDensForDivision; + Base::computeScalingFactor( ei, stack, [&] () + { + // compute the change in temperature + real64 const temp = m_temperature[ei]; + real64 const absTempChange = LvArray::math::abs( m_localSolution[stack.localRow + m_temperatureOffset] ); + if( stack.localMaxDeltaTemp < absTempChange ) + { + stack.localMaxDeltaTemp = absTempChange; + } + + m_temperatureScalingFactor[ei] = 1.0; + + if( temp > eps ) + { + real64 const relativeTempChange = absTempChange / temp; + if( relativeTempChange > m_maxRelativeTempChange ) + { + real64 const tempScalingFactor = m_maxRelativeTempChange / relativeTempChange; + m_temperatureScalingFactor[ei] = tempScalingFactor; + if( stack.localMinVal > tempScalingFactor ) + { + stack.localMinVal = tempScalingFactor; + } + if( stack.localMinTempScalingFactor > tempScalingFactor ) + { + stack.localMinTempScalingFactor = tempScalingFactor; + } + } + } + } ); + } + +protected: + + /// Max allowed changes in primary variables + real64 const m_maxRelativeTempChange; + + /// View on the primary variables + arrayView1d< real64 const > const m_temperature; + + /// View on the scaling factor + arrayView1d< real64 > const m_temperatureScalingFactor; + + /// Temperature offset in solution array + integer const m_temperatureOffset; +}; + +/** + * @class SolutionScalingKernelFactory + */ +class SolutionScalingKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] maxRelativePresChange the max allowed relative pressure change + * @param[in] maxAbsolutePresChange the max allowed absolute pressure change + * @param[in] maxRelativeTempChange the max allowed relative temperature change + * @param[in] maxCompFracChange the max allowed comp fraction change + * @param[in] maxRelativeCompdensChange the max allowed relative component density change + * @param[in] rankOffset the rank offset + * @param[in] numComp the number of components + * @param[in] dofKey the dof key to get dof numbers + * @param[in] subRegion the subRegion + * @param[in] localSolution the Newton update + */ + template< typename POLICY > + static SolutionScalingKernel::StackVariables + createAndLaunch( real64 const maxRelativePresChange, + real64 const maxAbsolutePresChange, + real64 const maxRelativeTempChange, + real64 const maxCompFracChange, + real64 const maxRelativeCompDensChange, + 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, + integer const temperatureOffset ) + { + SolutionScalingKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxRelativeTempChange, + maxCompFracChange, maxRelativeCompDensChange, + rankOffset, numComp, dofKey, subRegion, localSolution, + pressure, temperature, compDens, pressureScalingFactor, + compDensScalingFactor, temperatureScalingFactor, temperatureOffset ); + return thermalCompositionalMultiphaseBaseKernels:: + SolutionScalingKernel::launch< POLICY >( subRegion.size(), kernel ); + } + +}; + +} // namespace thermalCompositionalMultiphaseBaseKernels + +} // namespace geos + + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALSOLUTIONSCALINGKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp new file mode 100644 index 00000000000..d7bcb6068f1 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp @@ -0,0 +1,361 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AccumulationKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_ACCUMULATIONKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_ACCUMULATIONKERNELS_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/solid/CoupledSolidBase.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "codingUtilities/Utilities.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation + */ +template< typename SUBREGION_TYPE, integer NUM_DOF > +class AccumulationKernel +{ + +public: + + /// 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] 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 + */ + AccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : + m_rankOffset( rankOffset ), + m_dofNumber( subRegion.template getReference< array1d< globalIndex > >( dofKey ) ), + m_elemGhostRank( subRegion.ghostRank() ), + m_volume( subRegion.getElementVolume() ), + m_deltaVolume( subRegion.template getField< fields::flow::deltaVolume >() ), + m_porosity( solid.getPorosity() ), + m_dPoro_dPres( solid.getDporosity_dPressure() ), + m_density( fluid.density() ), + m_dDensity_dPres( fluid.dDensity_dPressure() ), + m_mass_n( subRegion.template getField< fields::flow::mass_n >() ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables + { +public: + + // Pore volume information + + /// Pore volume at time n+1 + real64 poreVolume = 0.0; + + /// Derivative of pore volume with respect to pressure + real64 dPoreVolume_dPres = 0.0; + + // Residual information + + /// Index of the local row corresponding to this element + localIndex localRow = -1; + + /// Index of the matrix row/column corresponding to the dof in this element + globalIndex dofIndices[numDof]{}; + + /// Storage for the element local residual vector + real64 localResidual[numEqn]{}; + + /// Storage for the element local Jacobian matrix + 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 pore volume + stack.poreVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * m_porosity[ei][0]; + stack.dPoreVolume_dPres = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; + + // 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] kernelOp the function used to customize the kernel + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + // Residual contribution is mass conservation in the cell + stack.localResidual[0] = stack.poreVolume * m_density[ei][0] - m_mass_n[ei]; + + // Derivative of residual wrt to pressure in the cell + stack.localJacobian[0][0] = stack.dPoreVolume_dPres * m_density[ei][0] + m_dDensity_dPres[ei][0] * stack.poreVolume; + + // Customize the kernel with this lambda + kernelOp(); + } + + /** + * @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 global residual and jacobian (no need for atomics here) + m_localMatrix.template addToRow< serialAtomic >( stack.localRow, + stack.dofIndices, + stack.localJacobian[0], + numDof ); + m_localRhs[stack.localRow] += stack.localResidual[0]; + + } + + /** + * @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.complete( ei, stack ); + } ); + } + +protected: + + /// 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; + arrayView1d< real64 const > const m_deltaVolume; + + /// Views on the porosity + arrayView2d< real64 const > const m_porosity; + arrayView2d< real64 const > const m_dPoro_dPres; + + /// Views on density + arrayView2d< real64 const > const m_density; + arrayView2d< real64 const > const m_dDensity_dPres; + + /// View on mass + arrayView1d< real64 const > const m_mass_n; + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; + +}; + +/** + * @class SurfaceElementAccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion + */ +class SurfaceElementAccumulationKernel : public AccumulationKernel< SurfaceElementSubRegion, 1 > +{ + +public: + + using Base = AccumulationKernel< SurfaceElementSubRegion, 1 >; + + /** + * @brief Constructor + * @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 + */ + SurfaceElementAccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SurfaceElementSubRegion const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ) + , m_creationMass( subRegion.getField< fields::flow::massCreated >() ) + {} + + /** + * @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, + Base::StackVariables & stack ) const + { + Base::computeAccumulation( ei, stack, [&] () + { + if( Base::m_mass_n[ei] > 1.1 * m_creationMass[ei] ) + { + stack.localResidual[0] += m_creationMass[ei] * 0.25; + } + } ); + } + +protected: + + arrayView1d< real64 const > const m_creationMass; + +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +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[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename SUBREGION_TYPE > + static void + createAndLaunch( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + if constexpr ( std::is_base_of_v< CellElementSubRegion, SUBREGION_TYPE > ) + { + integer constexpr NUM_DOF = 1; + AccumulationKernel< CellElementSubRegion, NUM_DOF > kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + AccumulationKernel< CellElementSubRegion, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } + else if constexpr ( std::is_base_of_v< SurfaceElementSubRegion, SUBREGION_TYPE > ) + { + SurfaceElementAccumulationKernel kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + SurfaceElementAccumulationKernel::launch< POLICY >( subRegion.size(), kernel ); + } + else + { + GEOS_UNUSED_VAR( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + GEOS_ERROR( "Unsupported subregion type: " << typeid(SUBREGION_TYPE).name() ); + } + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_ACCUMULATIONKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp new file mode 100644 index 00000000000..733a7013ac2 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/AquiferBCKernel.hpp @@ -0,0 +1,152 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file AquiferBCKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_AQUIFERBCKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_AQUIFERBCKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "fieldSpecification/AquiferBoundaryCondition.hpp" +#include "finiteVolume/BoundaryStencil.hpp" + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/******************************** AquiferBCKernel ********************************/ + +/** + * @brief Functions to assemble aquifer boundary condition contributions to residual and Jacobian + */ +struct AquiferBCKernel +{ + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + GEOS_HOST_DEVICE + static void + compute( real64 const & aquiferVolFlux, + real64 const & dAquiferVolFlux_dPres, + real64 const & aquiferDens, + real64 const & dens, + real64 const & dDens_dPres, + real64 const & dt, + real64 & localFlux, + real64 & localFluxJacobian ) + { + if( aquiferVolFlux > 0 ) // aquifer is upstream + { + localFlux -= dt * aquiferVolFlux * aquiferDens; + localFluxJacobian -= dt * dAquiferVolFlux_dPres * aquiferDens; + } + else // reservoir is upstream + { + localFlux -= dt * aquiferVolFlux * dens; + localFluxJacobian -= dt * (dAquiferVolFlux_dPres * dens + aquiferVolFlux * dDens_dPres); + } + } + + static void + launch( BoundaryStencil const & stencil, + globalIndex const rankOffset, + ElementViewConst< arrayView1d< globalIndex const > > const & dofNumber, + ElementViewConst< arrayView1d< integer const > > const & ghostRank, + AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, + real64 const & aquiferDens, + ElementViewConst< arrayView1d< real64 const > > const & pres, + ElementViewConst< arrayView1d< real64 const > > const & pres_n, + ElementViewConst< arrayView1d< real64 const > > const & gravCoef, + ElementViewConst< arrayView2d< real64 const > > const & dens, + ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres, + real64 const & timeAtBeginningOfStep, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + using Order = BoundaryStencil::Order; + + BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); + BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); + BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); + + forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + // working variables + real64 localFlux = 0.0; + real64 localFluxJacobian = 0.0; + + localIndex const er = seri( iconn, Order::ELEM ); + localIndex const esr = sesri( iconn, Order::ELEM ); + localIndex const ei = sefi( iconn, Order::ELEM ); + real64 const areaFraction = weight( iconn, Order::ELEM ); + + // compute the aquifer influx rate using the pressure influence function and the aquifer props + real64 dAquiferVolFlux_dPres = 0.0; + real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, + dt, + pres[er][esr][ei], + pres_n[er][esr][ei], + gravCoef[er][esr][ei], + areaFraction, + dAquiferVolFlux_dPres ); + + // compute the phase/component aquifer flux + AquiferBCKernel::compute( aquiferVolFlux, + dAquiferVolFlux_dPres, + aquiferDens, + dens[er][esr][ei][0], + dDens_dPres[er][esr][ei][0], + dt, + localFlux, + localFluxJacobian ); + + // Add to residual/jacobian + if( ghostRank[er][esr][ei] < 0 ) + { + globalIndex const globalRow = dofNumber[er][esr][ei]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( localMatrix.numRows(), localRow ); + + RAJA::atomicAdd( parallelDeviceAtomic{}, &localRhs[localRow], localFlux ); + localMatrix.addToRow< parallelDeviceAtomic >( localRow, + &dofNumber[er][esr][ei], + &localFluxJacobian, + 1 ); + } + } ); + } + +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_AQUIFERBCKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..e2a33419262 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/DirichletFluxComputeKernel.hpp @@ -0,0 +1,362 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file DirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_DIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_DIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "finiteVolume/BoundaryStencil.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp" +#include "codingUtilities/Utilities.hpp" + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public FluxComputeKernel< NUM_EQN, NUM_DOF, + BoundaryStencilWrapper > +{ +public: + + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; + using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; + using AbstractBase::m_dt; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_ghostRank; + using AbstractBase::m_gravCoef; + using AbstractBase::m_pres; + using AbstractBase::m_mob; + using AbstractBase::m_dMob_dPres; + using AbstractBase::m_dens; + using AbstractBase::m_dDens_dPres; + using AbstractBase::m_permeability; + using AbstractBase::m_dPerm_dPres; + using AbstractBase::m_localMatrix; + using AbstractBase::m_localRhs; + + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, + BoundaryStencilWrapper >; + using Base::numDof; + using Base::numEqn; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid wrapper + * @param[in] dofNumberAccessor + * @param[in] singlePhaseFlowAccessors + * @param[in] singlePhaseFluidAccessors + * @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 + */ + DirichletFluxComputeKernel( globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, + stencilWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_facePres( faceManager.getField< fields::flow::facePressure >() ), + m_faceGravCoef( faceManager.getField< fields::flow::gravityCoefficient >() ), + m_fluidWrapper( fluidWrapper ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + 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 GEOS_UNUSED_PARAM( size ), + localIndex GEOS_UNUSED_PARAM( numElems ) ) + {} + + /// Transmissibility + real64 transmissibility = 0.0; + + /// Indices of the matrix rows/columns corresponding to the dofs in this face + globalIndex dofColIndices[numDof]{}; + + /// Storage for the face local residual + real64 localFlux[numEqn]{}; + + /// Storage for the face local Jacobian + real64 localFluxJacobian[numEqn][numDof]{}; + + }; + + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const iconn, + StackVariables & stack ) const + { + globalIndex const offset = + m_dofNumber[m_seri( iconn, BoundaryStencil::Order::ELEM )][m_sesri( iconn, BoundaryStencil::Order::ELEM )][m_sei( iconn, BoundaryStencil::Order::ELEM )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[jdof] = offset + jdof; + } + } + + /** + * @brief Compute the local Dirichlet face 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] iconn the connection 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 + void computeFlux( localIndex const iconn, + StackVariables & stack, + FUNC && compFluxKernelOp = NoOpFunc{} ) const + { + using Order = BoundaryStencil::Order; + localIndex constexpr numElems = BoundaryStencil::maxNumPointsInFlux; + + stackArray1d< real64, numElems > mobility( numElems ); + stackArray1d< real64, numElems > dMobility_dP( numElems ); + + localIndex const er = m_seri( iconn, Order::ELEM ); + localIndex const esr = m_sesri( iconn, Order::ELEM ); + localIndex const ei = m_sei( iconn, Order::ELEM ); + localIndex const kf = m_sei( iconn, Order::FACE ); + + // Get flow quantities on the elem/face + real64 faceDens, faceVisc; + constitutive::SingleFluidBaseUpdate::computeValues( m_fluidWrapper, m_facePres[kf], faceDens, faceVisc ); + + mobility[Order::ELEM] = m_mob[er][esr][ei]; + singlePhaseBaseKernels::MobilityKernel::compute( faceDens, faceVisc, mobility[Order::FACE] ); + + dMobility_dP[Order::ELEM] = m_dMob_dPres[er][esr][ei]; + dMobility_dP[Order::FACE] = 0.0; + + // Compute average density + real64 const densMean = 0.5 * ( m_dens[er][esr][ei][0] + faceDens ); + real64 const dDens_dP = 0.5 * m_dDens_dPres[er][esr][ei][0]; + + // Evaluate potential difference + real64 const potDif = (m_pres[er][esr][ei] - m_facePres[kf]) + - densMean * (m_gravCoef[er][esr][ei] - m_faceGravCoef[kf]); + real64 const dPotDif_dP = 1.0 - dDens_dP * m_gravCoef[er][esr][ei]; + + real64 dTrans_dPerm[3]; + m_stencilWrapper.computeWeights( iconn, m_permeability, stack.transmissibility, dTrans_dPerm ); + real64 const dTrans_dPres = LvArray::tensorOps::AiBi< 3 >( dTrans_dPerm, m_dPerm_dPres[er][esr][ei][0] ); + + real64 const f = stack.transmissibility * potDif; + real64 const dF_dP = stack.transmissibility * dPotDif_dP + dTrans_dPres * potDif; + + // Upwind mobility + localIndex const k_up = ( potDif >= 0 ) ? Order::ELEM : Order::FACE; + real64 const mobility_up = mobility[k_up]; + real64 const dMobility_dP_up = dMobility_dP[k_up]; + + // call the lambda in the phase loop to allow the reuse of the fluxes and their derivatives + // possible use: assemble the derivatives wrt temperature, and the flux term of the energy equation for this phase + + compFluxKernelOp( er, esr, ei, kf, f, dF_dP, mobility_up, dMobility_dP_up ); + + // *** end of upwinding + + // Populate local flux vector and derivatives + + stack.localFlux[0] = m_dt * mobility[k_up] * f; + stack.localFluxJacobian[0][0] = m_dt * ( mobility_up * dF_dP + dMobility_dP_up * f ); + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && assemblyKernelOp = NoOpFunc{} ) const + { + using Order = BoundaryStencil::Order; + + localIndex const er = m_seri( iconn, Order::ELEM ); + localIndex const esr = m_sesri( iconn, Order::ELEM ); + localIndex const ei = m_sei( iconn, Order::ELEM ); + + if( m_ghostRank[er][esr][ei] < 0 ) + { + // Add to global residual/jacobian + globalIndex const dofIndex = m_dofNumber[er][esr][ei]; + localIndex const localRow = LvArray::integerConversion< localIndex >( dofIndex - m_rankOffset ); + + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow], stack.localFlux[0] ); + + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow, + stack.dofColIndices, + stack.localFluxJacobian[0], + numDof ); + + assemblyKernelOp( localRow ); + } + } + +protected: + + /// Views on face pressure, temperature, and composition + arrayView1d< real64 const > const m_facePres; + + /// View on the face gravity coefficient + arrayView1d< real64 const > const m_faceGravCoef; + + /// Reference to the fluid wrapper + FLUIDWRAPPER const m_fluidWrapper; + +}; + + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +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 string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the boundary stencil wrapper + * @param[in] fluidBase the single phase fluid constitutive model + * @param[in] dt time step size + * @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, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + BoundaryStencilWrapper const & stencilWrapper, + constitutive::SingleFluidBase & fluidBase, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_DOF = 1; + integer constexpr NUM_EQN = 1; + using kernelType = DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); + typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + + kernelType kernel( rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ); + + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } + +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_DIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp new file mode 100644 index 00000000000..9ee7550c9b7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp @@ -0,0 +1,55 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluidUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUIDUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUIDUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** FluidUpdateKernel ********************************/ + +struct FluidUpdateKernel +{ + template< typename FLUID_WRAPPER > + static void launch( FLUID_WRAPPER const & fluidWrapper, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & temp ) + { + forAll< parallelDevicePolicy<> >( fluidWrapper.numElems(), [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + for( localIndex q = 0; q < fluidWrapper.numGauss(); ++q ) + { + fluidWrapper.update( k, q, pres[k], temp[k] ); + } + } ); + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUIDUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp new file mode 100644 index 00000000000..8083ad10746 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp @@ -0,0 +1,383 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp" + + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/** + * @class FluxComputeKernel + * @tparam NUM_DOF number of degrees of freedom + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @brief Define the interface for the assembly kernel in charge of flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > +class FluxComputeKernel : public FluxComputeKernelBase +{ +public: + + /// 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_EQN; + + /// Maximum number of elements at the face + static constexpr localIndex maxNumElems = STENCILWRAPPER::maxNumPointsInFlux; + + /// Maximum number of connections at the face + static constexpr localIndex maxNumConns = STENCILWRAPPER::maxNumConnections; + + /// Maximum number of points in the stencil + static constexpr localIndex maxStencilSize = STENCILWRAPPER::maxStencilSize; + + /** + * @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] singlePhaseFlowAccessors + * @param[in] singlePhaseFluidAccessors + * @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 + */ + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : FluxComputeKernelBase( rankOffset, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_stencilWrapper( stencilWrapper ), + m_seri( stencilWrapper.getElementRegionIndices() ), + m_sesri( stencilWrapper.getElementSubRegionIndices() ), + m_sei( stencilWrapper.getElementIndices() ) + {} + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + 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, localIndex numElems ) + : stencilSize( size ), + numFluxElems( numElems ), + dofColIndices( size * numDof ), + localFlux( numElems * numEqn ), + localFluxJacobian( numElems * numEqn, size * numDof ) + {} + + // Stencil information + + /// Stencil size for a given connection + localIndex const stencilSize; + + /// Number of elements for a given connection + localIndex const numFluxElems; + + // Transmissibility and derivatives + + /// Transmissibility + real64 transmissibility[maxNumConns][2]{}; + /// Derivatives of transmissibility with respect to pressure + real64 dTrans_dPres[maxNumConns][2]{}; + + // 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 equations except volume balance) + stackArray1d< real64, maxNumElems * numEqn > localFlux; + /// Storage for the face local Jacobian matrix + stackArray2d< real64, maxNumElems * numEqn * maxStencilSize * numDof > localFluxJacobian; + + }; + + /** + * @brief Getter for the stencil size at this connection + * @param[in] iconn the connection index + * @return the size of the stencil at this connection + */ + GEOS_HOST_DEVICE + localIndex stencilSize( localIndex const iconn ) const + { return m_sei[iconn].size(); } + + /** + * @brief Getter for the number of elements at this connection + * @param[in] iconn the connection index + * @return the number of elements at this connection + */ + GEOS_HOST_DEVICE + localIndex numPointsInFlux( localIndex const iconn ) const + { return m_stencilWrapper.numPointsInFlux( iconn ); } + + /** + * @brief Performs the setup phase for the kernel. + * @param[in] iconn the connection index + * @param[in] stack the stack variables + */ + GEOS_HOST_DEVICE + void setup( localIndex const iconn, + StackVariables & stack ) const + { + // set degrees of freedom indices for this face + for( integer i = 0; i < stack.stencilSize; ++i ) + { + globalIndex const offset = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + + for( integer jdof = 0; jdof < numDof; ++jdof ) + { + stack.dofColIndices[i * numDof + jdof] = offset + 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 flux + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] NoOpFunc the function used to customize the computation of the flux + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + // first, compute the transmissibilities at this face + m_stencilWrapper.computeWeights( iconn, + m_permeability, + m_dPerm_dPres, + stack.transmissibility, + stack.dTrans_dPres ); + + localIndex k[2]; + localIndex connectionIndex = 0; + + for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] ) + { + for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] ) + { + real64 fluxVal = 0.0; + real64 dFlux_dTrans = 0.0; + real64 alpha = 0.0; + real64 mobility = 0.0; + real64 potGrad = 0.0; + real64 trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] }; + real64 dTrans[2] = { stack.dTrans_dPres[connectionIndex][0], stack.dTrans_dPres[connectionIndex][1] }; + real64 dFlux_dP[2] = {0.0, 0.0}; + localIndex const regionIndex[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )}; + localIndex const subRegionIndex[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )}; + localIndex const elementIndex[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; + + singlePhaseFluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, + trans, + dTrans, + m_pres, + m_gravCoef, + m_dens, + m_dDens_dPres, + m_mob, + m_dMob_dPres, + alpha, + mobility, + potGrad, + fluxVal, + dFlux_dP, + dFlux_dTrans ); + + // populate local flux vector and derivatives + stack.localFlux[k[0]*numEqn] += m_dt * fluxVal; + stack.localFlux[k[1]*numEqn] -= m_dt * fluxVal; + + for( integer ke = 0; ke < 2; ++ke ) + { + localIndex const localDofIndexPres = k[ke] * numDof; + stack.localFluxJacobian[k[0]*numEqn][localDofIndexPres] += m_dt * dFlux_dP[ke]; + stack.localFluxJacobian[k[1]*numEqn][localDofIndexPres] -= m_dt * dFlux_dP[ke]; + } + + // Customize the kernel with this lambda + kernelOp( k, regionIndex, subRegionIndex, elementIndex, connectionIndex, alpha, mobility, potGrad, fluxVal, dFlux_dP ); + + connectionIndex++; + } + } + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + template< typename FUNC = NoOpFunc > + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack, + FUNC && kernelOp = NoOpFunc{} ) const + { + // add contribution to residual and jacobian into: + // - the mass balance equation + // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels + for( integer i = 0; i < stack.numFluxElems; ++i ) + { + if( m_ghostRank[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )] < 0 ) + { + globalIndex const globalRow = m_dofNumber[m_seri( iconn, i )][m_sesri( iconn, i )][m_sei( iconn, i )]; + localIndex const localRow = LvArray::integerConversion< localIndex >( globalRow - m_rankOffset ); + GEOS_ASSERT_GE( localRow, 0 ); + GEOS_ASSERT_GT( m_localMatrix.numRows(), localRow ); + + RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[localRow], stack.localFlux[i * numEqn] ); + m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow, + stack.dofColIndices.data(), + stack.localFluxJacobian[i * numEqn].dataIfContiguous(), + stack.stencilSize * numDof ); + + // call the lambda to assemble additional terms, such as thermal terms + kernelOp( i, localRow ); + } + } + } + + /** + * @brief Performs the kernel launch + * @tparam POLICY the policy used in the RAJA kernels + * @tparam KERNEL_TYPE the kernel type + * @param[in] numConnections the number of connections + * @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 numConnections, + KERNEL_TYPE const & kernelComponent ) + { + GEOS_MARK_FUNCTION; + + forAll< POLICY >( numConnections, [=] GEOS_HOST_DEVICE ( localIndex const iconn ) + { + typename KERNEL_TYPE::StackVariables stack( kernelComponent.stencilSize( iconn ), + kernelComponent.numPointsInFlux( iconn ) ); + + kernelComponent.setup( iconn, stack ); + kernelComponent.computeFlux( iconn, stack ); + kernelComponent.complete( iconn, stack ); + } ); + } + + +protected: + + // Stencil information + + /// Reference to the stencil wrapper + STENCILWRAPPER const m_stencilWrapper; + + /// Connection to element maps + typename STENCILWRAPPER::IndexContainerViewConstType const m_seri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sesri; + typename STENCILWRAPPER::IndexContainerViewConstType const m_sei; +}; + +/** + * @class FluxComputeKernelFactory + */ +class FluxComputeKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch + * @tparam POLICY the policy used in the RAJA kernel + * @tparam STENCILWRAPPER the type of the stencil wrapper + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofKey string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename STENCILWRAPPER > + static void + createAndLaunch( globalIndex const rankOffset, + string const & dofKey, + string const & solverName, + ElementRegionManager const & elemManager, + STENCILWRAPPER const & stencilWrapper, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + integer constexpr NUM_EQN = 1; + integer constexpr NUM_DOF = 1; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + using kernelType = FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + typename kernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName ); + typename kernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permAccessors( elemManager, solverName ); + + kernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor, + flowAccessors, fluidAccessors, permAccessors, + dt, localMatrix, localRhs ); + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp new file mode 100644 index 00000000000..5a3896fdd79 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp @@ -0,0 +1,173 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file FluxComputeKernelBase.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNELBASE_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNELBASE_HPP + +#include "common/DataLayouts.hpp" +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" +#include "constitutive/fluid/singlefluid/SlurryFluidBase.hpp" +#include "constitutive/fluid/singlefluid/SlurryFluidFields.hpp" +#include "constitutive/permeability/PermeabilityBase.hpp" +#include "constitutive/permeability/PermeabilityFields.hpp" +#include "linearAlgebra/interfaces/InterfaceTypes.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/StencilAccessors.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" + +namespace geos +{ + +namespace singlePhaseFVMKernels +{ + +/******************************** FluxComputeKernelBase ********************************/ + +/** + * @brief Base class for FluxComputeKernel that holds all data not dependent + * on template parameters (like stencil type and number of dofs). + */ +class FluxComputeKernelBase +{ +public: + + /** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using DofNumberAccessor = ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > >; + + using SinglePhaseFlowAccessors = + StencilAccessors< fields::ghostRank, + fields::flow::pressure, + fields::flow::pressure_n, + fields::flow::gravityCoefficient, + fields::flow::mobility, + fields::flow::dMobility_dPressure >; + + using SinglePhaseFluidAccessors = + StencilMaterialAccessors< constitutive::SingleFluidBase, + fields::singlefluid::density, + fields::singlefluid::dDensity_dPressure >; + + using SlurryFluidAccessors = + StencilMaterialAccessors< constitutive::SlurryFluidBase, + fields::singlefluid::density, + fields::singlefluid::dDensity_dPressure >; + + using PermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure >; + + using ProppantPermeabilityAccessors = + StencilMaterialAccessors< constitutive::PermeabilityBase, + fields::permeability::permeability, + fields::permeability::dPerm_dPressure, + fields::permeability::dPerm_dDispJump, + fields::permeability::permeabilityMultiplier >; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of my MPI rank + * @param[in] dofNumberAccessor accessor for the dof numbers + * @param[in] singleFlowAccessors accessor for wrappers registered by the solver + * @param[in] singlePhaseFluidAccessors accessor for wrappers registered by the singlefluid model + * @param[in] permeabilityAccessors accessor for wrappers registered by the permeability model + * @param[in] dt time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + FluxComputeKernelBase( globalIndex const rankOffset, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : m_rankOffset( rankOffset ), + m_dt( dt ), + m_dofNumber( dofNumberAccessor.toNestedViewConst() ), + m_permeability( permeabilityAccessors.get( fields::permeability::permeability {} ) ), + m_dPerm_dPres( permeabilityAccessors.get( fields::permeability::dPerm_dPressure {} ) ), + m_ghostRank( singlePhaseFlowAccessors.get( fields::ghostRank {} ) ), + m_gravCoef( singlePhaseFlowAccessors.get( fields::flow::gravityCoefficient {} ) ), + m_pres( singlePhaseFlowAccessors.get( fields::flow::pressure {} ) ), + m_mob( singlePhaseFlowAccessors.get( fields::flow::mobility {} ) ), + m_dMob_dPres( singlePhaseFlowAccessors.get( fields::flow::dMobility_dPressure {} ) ), + m_dens( singlePhaseFluidAccessors.get( fields::singlefluid::density {} ) ), + m_dDens_dPres( singlePhaseFluidAccessors.get( fields::singlefluid::dDensity_dPressure {} ) ), + m_localMatrix( localMatrix ), + m_localRhs( localRhs ) + {} + +protected: + + /// Offset for my MPI rank + globalIndex const m_rankOffset; + + /// Time step size + real64 const m_dt; + + /// Views on dof numbers + ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber; + + /// Views on permeability + ElementViewConst< arrayView3d< real64 const > > m_permeability; + ElementViewConst< arrayView3d< real64 const > > m_dPerm_dPres; + + /// Views on ghost rank numbers and gravity coefficients + ElementViewConst< arrayView1d< integer const > > const m_ghostRank; + ElementViewConst< arrayView1d< real64 const > > const m_gravCoef; + + // Primary and secondary variables + /// Views on pressure + ElementViewConst< arrayView1d< real64 const > > const m_pres; + + /// Views on fluid mobility + ElementViewConst< arrayView1d< real64 const > > const m_mob; + ElementViewConst< arrayView1d< real64 const > > const m_dMob_dPres; + + /// Views on fluid density + ElementViewConst< arrayView2d< real64 const > > const m_dens; + ElementViewConst< arrayView2d< real64 const > > const m_dDens_dPres; + + // Residual and jacobian + + /// View on the local CRS matrix + CRSMatrixView< real64, globalIndex const > const m_localMatrix; + /// View on the local RHS + arrayView1d< real64 > const m_localRhs; +}; + +} // namespace singlePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXCOMPUTEKERNELBASE_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp similarity index 75% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp index 0e4ae5ba2b4..07f81dfd2f0 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp @@ -17,22 +17,24 @@ * @file FluxKernelsHelper.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLUXKERNELSHELPER_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLUXKERNELSHELPER_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP #include "common/DataTypes.hpp" -#include "common/GEOS_RAJA_Interface.hpp" -#include "finiteVolume/BoundaryStencil.hpp" -#include "linearAlgebra/interfaces/InterfaceTypes.hpp" #include "mesh/ElementRegionManager.hpp" -#include "fieldSpecification/AquiferBoundaryCondition.hpp" namespace geos { -namespace fluxKernelsHelper +namespace singlePhaseFluxKernelsHelper { +/** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; @@ -283,69 +285,8 @@ void computeConductiveFlux( localIndex const ( &seri )[2], } } -/******************************** AquiferBCKernel ********************************/ - -/** - * @brief Function to sum the aquiferBC fluxes (as later save them) at the end of the time step - * This function is applicable for both single-phase and multiphase flow - */ -struct AquiferBCKernel -{ - - /** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - - static real64 - sumFluxes( BoundaryStencil const & stencil, - AquiferBoundaryCondition::KernelWrapper const & aquiferBCWrapper, - ElementViewConst< arrayView1d< real64 const > > const & pres, - ElementViewConst< arrayView1d< real64 const > > const & presOld, - ElementViewConst< arrayView1d< real64 const > > const & gravCoef, - real64 const & timeAtBeginningOfStep, - real64 const & dt ) - { - using Order = BoundaryStencil::Order; - - BoundaryStencil::IndexContainerViewConstType const & seri = stencil.getElementRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sesri = stencil.getElementSubRegionIndices(); - BoundaryStencil::IndexContainerViewConstType const & sefi = stencil.getElementIndices(); - BoundaryStencil::WeightContainerViewConstType const & weight = stencil.getWeights(); - - RAJA::ReduceSum< parallelDeviceReduce, real64 > targetSetSumFluxes( 0.0 ); - - forAll< parallelDevicePolicy<> >( stencil.size(), [=] GEOS_HOST_DEVICE ( localIndex const iconn ) - { - localIndex const er = seri( iconn, Order::ELEM ); - localIndex const esr = sesri( iconn, Order::ELEM ); - localIndex const ei = sefi( iconn, Order::ELEM ); - real64 const areaFraction = weight( iconn, Order::ELEM ); - - // compute the aquifer influx rate using the pressure influence function and the aquifer props - real64 dAquiferVolFlux_dPres = 0.0; - real64 const aquiferVolFlux = aquiferBCWrapper.compute( timeAtBeginningOfStep, - dt, - pres[er][esr][ei], - presOld[er][esr][ei], - gravCoef[er][esr][ei], - areaFraction, - dAquiferVolFlux_dPres ); - targetSetSumFluxes += aquiferVolFlux; - } ); - return targetSetSumFluxes.get(); - } - -}; - - -} // namespace fluxKernelsHelper +} // namespace singlePhaseFluxKernelsHelper } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_FLUXKERNELSHELPER_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp new file mode 100644 index 00000000000..fe08f309833 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/HydrostaticPressureKernel.hpp @@ -0,0 +1,213 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file HydrostaticPressureKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYDROSTATICPRESSUREKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYDROSTATICPRESSUREKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** HydrostaticPressureKernel ********************************/ + +struct HydrostaticPressureKernel +{ + + template< typename FLUID_WRAPPER > + static bool + computeHydrostaticPressure( integer const maxNumEquilIterations, + real64 const & equilTolerance, + real64 const (&gravVector)[ 3 ], + FLUID_WRAPPER fluidWrapper, + real64 const & refElevation, + real64 const & refPres, + real64 const & refDens, + real64 const & newElevation, + real64 & newPres, + real64 & newDens ) + { + // Step 1: guess the pressure with the refDensity + + real64 const gravCoef = gravVector[2] * ( refElevation - newElevation ); + real64 pres0 = refPres - refDens * gravCoef; + real64 pres1 = 0.0; + + // Step 2: compute the mass density at this elevation using the guess, and update pressure + + real64 dens = 0.0; + real64 visc = 0.0; + constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, + pres0, + dens, + visc ); + pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; + + // Step 3: fixed-point iteration until convergence + + bool equilHasConverged = false; + for( localIndex eqIter = 0; eqIter < maxNumEquilIterations; ++eqIter ) + { + + // check convergence + equilHasConverged = ( LvArray::math::abs( pres0 - pres1 ) < equilTolerance ); + pres0 = pres1; + + // if converged, move on + if( equilHasConverged ) + { + break; + } + + // compute the density at this elevation using the previous pressure, and compute the new pressure + constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, + pres0, + dens, + visc ); + pres1 = refPres - 0.5 * ( refDens + dens ) * gravCoef; + } + + // Step 4: save the hydrostatic pressure and the corresponding density + + newPres = pres1; + newDens = dens; + + return equilHasConverged; + } + + + template< typename FLUID_WRAPPER > + static bool + launch( localIndex const size, + integer const maxNumEquilIterations, + real64 const equilTolerance, + real64 const (&gravVector)[ 3 ], + real64 const & minElevation, + real64 const & elevationIncrement, + real64 const & datumElevation, + real64 const & datumPres, + FLUID_WRAPPER fluidWrapper, + arrayView1d< arrayView1d< real64 > const > elevationValues, + arrayView1d< real64 > pressureValues ) + { + bool hasConverged = true; + + // Step 1: compute the mass density at the datum elevation + + real64 datumDens = 0.0; + real64 datumVisc = 0.0; + + constitutive::SingleFluidBaseUpdate::computeValues( fluidWrapper, + datumPres, + datumDens, + datumVisc ); + + // Step 2: find the closest elevation to datumElevation + + forAll< parallelHostPolicy >( size, [=] ( localIndex const i ) + { + real64 const elevation = minElevation + i * elevationIncrement; + elevationValues[0][i] = elevation; + } ); + integer const iRef = LvArray::sortedArrayManipulation::find( elevationValues[0].begin(), + elevationValues[0].size(), + datumElevation ); + + + // Step 3: compute the mass density and pressure at the reference elevation + + array1d< real64 > dens( pressureValues.size() ); + + bool const hasConvergedRef = + computeHydrostaticPressure( maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + datumElevation, + datumPres, + datumDens, + elevationValues[0][iRef], + pressureValues[iRef], + dens[iRef] ); + if( !hasConvergedRef ) + { + return false; + } + + + // Step 4: for each elevation above the reference elevation, compute the pressure + + localIndex const numEntriesAboveRef = size - iRef - 1; + forAll< serialPolicy >( numEntriesAboveRef, [=, &hasConverged] ( localIndex const i ) + { + bool const hasConvergedAboveRef = + computeHydrostaticPressure( maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + elevationValues[0][iRef+i], + pressureValues[iRef+i], + dens[iRef+i], + elevationValues[0][iRef+i+1], + pressureValues[iRef+i+1], + dens[iRef+i+1] ); + if( !hasConvergedAboveRef ) + { + hasConverged = false; + } + + + } ); + + // Step 5: for each elevation below the reference elevation, compute the pressure + + localIndex const numEntriesBelowRef = iRef; + forAll< serialPolicy >( numEntriesBelowRef, [=, &hasConverged] ( localIndex const i ) + { + bool const hasConvergedBelowRef = + computeHydrostaticPressure( maxNumEquilIterations, + equilTolerance, + gravVector, + fluidWrapper, + elevationValues[0][iRef-i], + pressureValues[iRef-i], + dens[iRef-i], + elevationValues[0][iRef-i-1], + pressureValues[iRef-i-1], + dens[iRef-i-1] ); + if( !hasConvergedBelowRef ) + { + hasConverged = false; + } + } ); + + return hasConverged; + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYDROSTATICPRESSUREKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp new file mode 100644 index 00000000000..22f6470f5f3 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp @@ -0,0 +1,149 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file MobilityKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_MOBILITYKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_MOBILITYKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** MobilityKernel ********************************/ + +struct MobilityKernel +{ + // Isothermal version + GEOS_HOST_DEVICE + inline + static void + compute( real64 const & dens, + real64 const & dDens_dPres, + real64 const & visc, + real64 const & dVisc_dPres, + real64 & mob, + real64 & dMob_dPres ) + { + mob = dens / visc; + dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; + } + +// Thermal version + GEOS_HOST_DEVICE + inline + static void + compute( real64 const & dens, + real64 const & dDens_dPres, + real64 const & dDens_dTemp, + real64 const & visc, + real64 const & dVisc_dPres, + real64 const & dVisc_dTemp, + real64 & mob, + real64 & dMob_dPres, + real64 & dMob_dTemp ) + { + mob = dens / visc; + dMob_dPres = dDens_dPres / visc - mob / visc * dVisc_dPres; + dMob_dTemp = dDens_dTemp / visc - mob / visc * dVisc_dTemp; + } + +// Value-only (no derivatives) version + GEOS_HOST_DEVICE + inline + static void + compute( real64 const & dens, + real64 const & visc, + real64 & mob ) + { + mob = dens / visc; + } + + // Isothermal version + template< typename POLICY > + static void launch( localIndex const size, + arrayView2d< real64 const > const & dens, + arrayView2d< real64 const > const & dDens_dPres, + arrayView2d< real64 const > const & visc, + arrayView2d< real64 const > const & dVisc_dPres, + arrayView1d< real64 > const & mob, + arrayView1d< real64 > const & dMob_dPres ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + compute( dens[a][0], + dDens_dPres[a][0], + visc[a][0], + dVisc_dPres[a][0], + mob[a], + dMob_dPres[a] ); + } ); + } + + // Thermal version + template< typename POLICY > + static void launch( localIndex const size, + arrayView2d< real64 const > const & dens, + arrayView2d< real64 const > const & dDens_dPres, + arrayView2d< real64 const > const & dDens_dTemp, + arrayView2d< real64 const > const & visc, + arrayView2d< real64 const > const & dVisc_dPres, + arrayView2d< real64 const > const & dVisc_dTemp, + arrayView1d< real64 > const & mob, + arrayView1d< real64 > const & dMob_dPres, + arrayView1d< real64 > const & dMob_dTemp ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + compute( dens[a][0], + dDens_dPres[a][0], + dDens_dTemp[a][0], + visc[a][0], + dVisc_dPres[a][0], + dVisc_dTemp[a][0], + mob[a], + dMob_dPres[a], + dMob_dTemp[a] ); + } ); + } + +// Value-only (no derivatives) version + template< typename POLICY > + static void launch( localIndex const size, + arrayView2d< real64 const > const & dens, + arrayView2d< real64 const > const & visc, + arrayView1d< real64 > const & mob ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const a ) + { + compute( dens[a][0], + visc[a][0], + mob[a] ); + } ); + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_MOBILITYKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp new file mode 100644 index 00000000000..f88ef04eb96 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ResidualNormKernel.hpp @@ -0,0 +1,268 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ResidualNormKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_RESIDUALNORMKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_RESIDUALNORMKERNEL_HPP + +#include "physicsSolvers/PhysicsSolverBaseKernels.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** ResidualNormKernel ********************************/ + +/** + * @class IsothermalResidualNormKernel + */ +class IsothermalResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 1 > +{ +public: + + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 1 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + IsothermalResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_mass_n( subRegion.template getField< fields::flow::mass_n >() ) + {} + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + real64 const massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); + stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; + stack.localNormalizer[0] += massNormalizer; + } + + +protected: + + /// View on mass at the previous converged time step + arrayView1d< real64 const > const m_mass_n; + +}; + +/** + * @class ThermalResidualNormKernel + */ +class ThermalResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBase< 2 > +{ +public: + + using Base = physicsSolverBaseKernels::ResidualNormKernelBase< 2 >; + using Base::m_minNormalizer; + using Base::m_rankOffset; + using Base::m_localResidual; + using Base::m_dofNumber; + + ThermalResidualNormKernel( globalIndex const rankOffset, + arrayView1d< real64 const > const & localResidual, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< localIndex const > const & ghostRank, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer ) + : Base( rankOffset, + localResidual, + dofNumber, + ghostRank, + minNormalizer ), + m_mass_n( subRegion.template getField< fields::flow::mass_n >() ), + m_energy_n( subRegion.template getField< fields::flow::energy_n >() ) + {} + + GEOS_HOST_DEVICE + void computeMassEnergyNormalizers( localIndex const ei, + real64 & massNormalizer, + real64 & energyNormalizer ) const + { + massNormalizer = LvArray::math::max( m_minNormalizer, m_mass_n[ei] ); + energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( m_energy_n[ei] ) ); // energy can be negative + } + + GEOS_HOST_DEVICE + virtual void computeLinf( localIndex const ei, + LinfStackVariables & stack ) const override + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + + // step 1: mass residual + + real64 const valMass = LvArray::math::abs( m_localResidual[stack.localRow] ) / massNormalizer; + if( valMass > stack.localValue[0] ) + { + stack.localValue[0] = valMass; + } + + // step 2: energy residual + real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + 1] ) / energyNormalizer; + if( valEnergy > stack.localValue[1] ) + { + stack.localValue[1] = valEnergy; + } + } + + GEOS_HOST_DEVICE + virtual void computeL2( localIndex const ei, + L2StackVariables & stack ) const override + { + real64 massNormalizer = 0.0, energyNormalizer = 0.0; + computeMassEnergyNormalizers( ei, massNormalizer, energyNormalizer ); + + // step 1: mass residual + + stack.localValue[0] += m_localResidual[stack.localRow] * m_localResidual[stack.localRow]; + stack.localNormalizer[0] += massNormalizer; + + // step 2: energy residual + + stack.localValue[1] += m_localResidual[stack.localRow + 1] * m_localResidual[stack.localRow + 1]; + stack.localNormalizer[1] += energyNormalizer; + } + + +protected: + + /// View on mass at the previous converged time step + arrayView1d< real64 const > const m_mass_n; + + /// View on energy at the previous converged time step + arrayView1d< real64 const > const m_energy_n; + +}; + +/** + * @class ResidualNormKernelFactory + */ +class ResidualNormKernelFactory +{ +public: + + /** + * @brief Create a new kernel and launch (isothermal version) + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @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 element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + globalIndex const rankOffset, + string const dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer, + real64 (& residualNorm)[1], + real64 (& residualNormalizer)[1] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + IsothermalResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + IsothermalResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + IsothermalResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + } + + /** + * @brief Create a new kernel and launch (thermal version) + * @tparam POLICY the policy used in the RAJA kernel + * @param[in] normType the type of norm used (Linf or L2) + * @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 element subregion + * @param[in] fluid the fluid model + * @param[in] solid the solid model + * @param[in] solidInternalEnergy the solid internal energy model + * @param[out] residualNorm the residual norm on the subRegion + * @param[out] residualNormalizer the residual normalizer on the subRegion + */ + template< typename POLICY > + static void + createAndLaunch( physicsSolverBaseKernels::NormType const normType, + globalIndex const rankOffset, + string const & dofKey, + arrayView1d< real64 const > const & localResidual, + ElementSubRegionBase const & subRegion, + real64 const minNormalizer, + real64 (& residualNorm)[2], + real64 (& residualNormalizer)[2] ) + { + arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey ); + arrayView1d< integer const > const ghostRank = subRegion.ghostRank(); + + ThermalResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank, subRegion, minNormalizer ); + if( normType == physicsSolverBaseKernels::NormType::Linf ) + { + ThermalResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm ); + } + else // L2 norm + { + ThermalResidualNormKernel::launchL2< POLICY >( subRegion.size(), kernel, residualNorm, residualNormalizer ); + } + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_RESIDUALNORMKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseHybridFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp similarity index 99% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseHybridFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp index d2fc6b39da9..13e5eeabfcb 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseHybridFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SinglePhaseHybridFVMKernels.hpp @@ -17,8 +17,8 @@ * @file SinglePhaseHybridFVMKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEHYBRIDFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEHYBRIDFVMKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYBRIDFVMKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYBRIDFVMKERNELS_HPP #include "common/DataTypes.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" @@ -37,7 +37,7 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp" #include "physicsSolvers/fluidFlow/kernels/HybridFVMHelperKernels.hpp" #include "physicsSolvers/PhysicsSolverBaseKernels.hpp" #include "codingUtilities/Utilities.hpp" @@ -959,4 +959,4 @@ class ResidualNormKernelFactory } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEHYBRIDFVMKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_HYBRIDFVMKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp new file mode 100644 index 00000000000..4ed3658e569 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolidInternalEnergyUpdateKernel.hpp @@ -0,0 +1,54 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolidInternalEnergyUpdateKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLIDINTERNALENERGYUPDATEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLIDINTERNALENERGYUPDATEKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseBaseKernels +{ + +/******************************** SolidInternalEnergyUpdateKernel ********************************/ + +struct SolidInternalEnergyUpdateKernel +{ + + template< typename POLICY, typename SOLID_INTERNAL_ENERGY_WRAPPER > + static void + launch( localIndex const size, + SOLID_INTERNAL_ENERGY_WRAPPER const & solidInternalEnergyWrapper, + arrayView1d< real64 const > const & temp ) + { + forAll< POLICY >( size, [=] GEOS_HOST_DEVICE ( localIndex const k ) + { + solidInternalEnergyWrapper.update( k, temp[k] ); + } ); + } +}; + +} // namespace thermalSinglePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SOLIDINTERNALENERGYUPDATEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp new file mode 100644 index 00000000000..29a22e422f7 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp @@ -0,0 +1,72 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionCheckKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONCHECKKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONCHECKKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** SolutionCheckKernel ********************************/ + +struct SolutionCheckKernel +{ + template< typename POLICY > + static std::pair< integer, real64 > launch( arrayView1d< real64 const > const & localSolution, + globalIndex const rankOffset, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< integer const > const & ghostRank, + arrayView1d< real64 const > const & pres, + real64 const scalingFactor ) + { + RAJA::ReduceSum< ReducePolicy< POLICY >, integer > numNegativePressures( 0 ); + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > minPres( 0.0 ); + + forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) + { + localIndex const lid = dofNumber[ei] - rankOffset; + real64 const newPres = pres[ei] + scalingFactor * localSolution[lid]; + + if( newPres < 0.0 ) + { + numNegativePressures += 1; + minPres.min( newPres ); + } + } + + } ); + + return { numNegativePressures.get(), minPres.get() }; + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONCHECKKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp new file mode 100644 index 00000000000..5994d972e3b --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/SolutionScalingKernel.hpp @@ -0,0 +1,75 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file SolutionScalingKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONSCALINGKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONSCALINGKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** SolutionScalingKernel ********************************/ + +struct SolutionScalingKernel +{ + template< typename POLICY > + static std::pair< real64, real64 > launch( arrayView1d< real64 const > const & localSolution, + globalIndex const rankOffset, + arrayView1d< globalIndex const > const & dofNumber, + arrayView1d< integer const > const & ghostRank, + real64 const maxAbsolutePresChange ) + { + RAJA::ReduceMin< ReducePolicy< POLICY >, real64 > scalingFactor( 1.0 ); + RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxDeltaPres( 0.0 ); + + forAll< POLICY >( dofNumber.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei ) mutable + { + if( ghostRank[ei] < 0 && dofNumber[ei] >= 0 ) + { + localIndex const lid = dofNumber[ei] - rankOffset; + + // compute the change in pressure + real64 const absPresChange = LvArray::math::abs( localSolution[lid] ); + maxDeltaPres.max( absPresChange ); + + // maxAbsolutePresChange <= 0.0 means that scaling is disabled, and we are only collecting maxDeltaPres in this kernel + if( maxAbsolutePresChange > 0.0 && absPresChange > maxAbsolutePresChange ) + { + real64 const presScalingFactor = maxAbsolutePresChange / absPresChange; + scalingFactor.min( presScalingFactor ); + } + } + + } ); + + return { scalingFactor.get(), maxDeltaPres.get() }; + } + +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_SOLUTIONSCALINGKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/StabilizedSinglePhaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp similarity index 86% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/StabilizedSinglePhaseFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp index 98963a98ea2..88d4cc4ce73 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/StabilizedSinglePhaseFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StabilizedFluxComputeKernel.hpp @@ -14,13 +14,13 @@ */ /** - * @file StabilizedSinglePhaseFVMKernels.hpp + * @file StabilizedFluxComputeKernel.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDSINGLEPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDSINGLEPHASEFVMKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STABILIZEDFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STABILIZEDFLUXCOMPUTEKERNEL_HPP -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" namespace geos { @@ -28,24 +28,23 @@ namespace geos namespace stabilizedSinglePhaseFVMKernels { - -/******************************** FaceBasedAssemblyKernel ********************************/ +/******************************** FluxComputeKernel ********************************/ /** - * @class FaceBasedAssemblyKernel + * @class FluxComputeKernel * @tparam NUM_DOF number of degrees of freedom * @tparam STENCILWRAPPER the type of the stencil wrapper * @brief Define the interface for the assembly kernel in charge of flux terms */ template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER > +class FluxComputeKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER > { public: template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; @@ -67,7 +66,7 @@ class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyK using AbstractBase::m_gravCoef; using AbstractBase::m_pres; - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; using Base::numDof; using Base::numEqn; using Base::maxNumElems; @@ -92,17 +91,17 @@ class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyK * @param[inout] localMatrix the local CRS matrix * @param[inout] localRhs the local right-hand side vector */ - FaceBasedAssemblyKernel( globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - StabSinglePhaseFlowAccessors const & stabSinglePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - StabSinglePhaseFluidAccessors const & stabSinglePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + StabSinglePhaseFlowAccessors const & stabSinglePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + StabSinglePhaseFluidAccessors const & stabSinglePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) : Base( rankOffset, stencilWrapper, dofNumberAccessor, @@ -248,9 +247,9 @@ class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyK }; /** - * @class FaceBasedAssemblyKernelFactory + * @class FluxComputeKernelFactory */ -class FaceBasedAssemblyKernelFactory +class FluxComputeKernelFactory { public: @@ -286,7 +285,7 @@ class FaceBasedAssemblyKernelFactory elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - using KERNEL_TYPE = FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + using KERNEL_TYPE = FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; typename KERNEL_TYPE::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); typename KERNEL_TYPE::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); typename KERNEL_TYPE::StabSinglePhaseFlowAccessors stabSinglePhaseFlowAccessors( elemManager, solverName ); @@ -306,4 +305,4 @@ class FaceBasedAssemblyKernelFactory } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_STABILIZEDSINGLEPHASEFVMKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STABILIZEDFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp new file mode 100644 index 00000000000..59e0d267dc8 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/StatisticsKernel.hpp @@ -0,0 +1,133 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file StatisticsKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STATISTICSKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STATISTICSKERNEL_HPP + +#include "common/DataTypes.hpp" +#include "common/GEOS_RAJA_Interface.hpp" + +namespace geos +{ + +namespace singlePhaseBaseKernels +{ + +/******************************** StatisticsKernel ********************************/ + +struct StatisticsKernel +{ + static void + saveDeltaPressure( localIndex const size, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & initPres, + arrayView1d< real64 > const & deltaPres ) + { + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + deltaPres[ei] = pres[ei] - initPres[ei]; + } ); + } + + static void + launch( localIndex const size, + arrayView1d< integer const > const & elemGhostRank, + arrayView1d< real64 const > const & volume, + arrayView1d< real64 const > const & pres, + arrayView1d< real64 const > const & deltaPres, + arrayView1d< real64 const > const & temp, + arrayView1d< real64 const > const & refPorosity, + arrayView2d< real64 const > const & porosity, + arrayView2d< real64 const > const & density, + real64 & minPres, + real64 & avgPresNumerator, + real64 & maxPres, + real64 & minDeltaPres, + real64 & maxDeltaPres, + real64 & minTemp, + real64 & avgTempNumerator, + real64 & maxTemp, + real64 & totalUncompactedPoreVol, + real64 & totalPoreVol, + real64 & totalMass ) + { + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgPresNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxPres( -LvArray::NumericLimits< real64 >::max ); + + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinDeltaPres( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxDeltaPres( -LvArray::NumericLimits< real64 >::max ); + + RAJA::ReduceMin< parallelDeviceReduce, real64 > subRegionMinTemp( LvArray::NumericLimits< real64 >::max ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionAvgTempNumerator( 0.0 ); + RAJA::ReduceMax< parallelDeviceReduce, real64 > subRegionMaxTemp( -LvArray::NumericLimits< real64 >::max ); + + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalUncompactedPoreVol( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalPoreVol( 0.0 ); + RAJA::ReduceSum< parallelDeviceReduce, real64 > subRegionTotalMass( 0.0 ); + + forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const ei ) + { + if( elemGhostRank[ei] >= 0 ) + { + return; + } + + // To match our "reference", we have to use reference porosity here, not the actual porosity when we compute averages + real64 const uncompactedPoreVol = volume[ei] * refPorosity[ei]; + real64 const dynamicPoreVol = volume[ei] * porosity[ei][0]; + + subRegionMinPres.min( pres[ei] ); + subRegionAvgPresNumerator += uncompactedPoreVol * pres[ei]; + subRegionMaxPres.max( pres[ei] ); + + subRegionMinDeltaPres.min( deltaPres[ei] ); + subRegionMaxDeltaPres.max( deltaPres[ei] ); + + subRegionMinTemp.min( temp[ei] ); + subRegionAvgTempNumerator += uncompactedPoreVol * temp[ei]; + subRegionMaxTemp.max( temp[ei] ); + + subRegionTotalUncompactedPoreVol += uncompactedPoreVol; + subRegionTotalPoreVol += dynamicPoreVol; + subRegionTotalMass += dynamicPoreVol * density[ei][0]; + } ); + + minPres = subRegionMinPres.get(); + avgPresNumerator = subRegionAvgPresNumerator.get(); + maxPres = subRegionMaxPres.get(); + + minDeltaPres = subRegionMinDeltaPres.get(); + maxDeltaPres = subRegionMaxDeltaPres.get(); + + minTemp = subRegionMinTemp.get(); + avgTempNumerator = subRegionAvgTempNumerator.get(); + maxTemp = subRegionMaxTemp.get(); + + totalUncompactedPoreVol = subRegionTotalUncompactedPoreVol.get(); + totalPoreVol = subRegionTotalPoreVol.get(); + totalMass = subRegionTotalMass.get(); + } +}; + +} // namespace singlePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_STATISTICSKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp new file mode 100644 index 00000000000..792558b5b2e --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalAccumulationKernels.hpp @@ -0,0 +1,338 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalAccumulationKernels.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALACCUMULATIONKERNELS_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALACCUMULATIONKERNELS_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/AccumulationKernels.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseBaseKernels +{ + +/******************************** AccumulationKernel ********************************/ + +/** + * @class AccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation + */ +template< typename SUBREGION_TYPE, integer NUM_DOF > +class AccumulationKernel : public singlePhaseBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF > +{ + +public: + + using Base = singlePhaseBaseKernels::AccumulationKernel< SUBREGION_TYPE, NUM_DOF >; + using Base::numDof; + using Base::numEqn; + using Base::m_rankOffset; + using Base::m_dofNumber; + using Base::m_elemGhostRank; + using Base::m_volume; + using Base::m_deltaVolume; + using Base::m_porosity; + using Base::m_dPoro_dPres; + using Base::m_density; + using Base::m_dDensity_dPres; + using Base::m_localMatrix; + using Base::m_localRhs; + + /** + * @brief Constructor + * @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 + */ + AccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ), + m_dDensity_dTemp( fluid.dDensity_dTemperature() ), + m_dPoro_dTemp( solid.getDporosity_dTemperature() ), + m_internalEnergy( fluid.internalEnergy() ), + m_dInternalEnergy_dPres( fluid.dInternalEnergy_dPressure() ), + m_dInternalEnergy_dTemp( fluid.dInternalEnergy_dTemperature() ), + m_rockInternalEnergy( solid.getInternalEnergy() ), + m_dRockInternalEnergy_dTemp( solid.getDinternalEnergy_dTemperature() ), + m_energy_n( subRegion.template getField< fields::flow::energy_n >() ) + {} + + /** + * @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::poreVolume; + using Base::StackVariables::dPoreVolume_dPres; + using Base::StackVariables::localRow; + using Base::StackVariables::dofIndices; + using Base::StackVariables::localResidual; + using Base::StackVariables::localJacobian; + + /// Derivative of pore volume with respect to temperature + real64 dPoreVolume_dTemp = 0.0; + + // Solid energy + + /// Solid energy at time n+1 + real64 solidEnergy = 0.0; + + /// Derivative of solid internal energy with respect to pressure + real64 dSolidEnergy_dPres = 0.0; + + /// Derivative of solid internal energy with respect to temperature + real64 dSolidEnergy_dTemp = 0.0; + }; + + + /** + * @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 ); + + stack.dPoreVolume_dTemp = ( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; + + // initialize the solid volume + real64 const solidVolume = ( m_volume[ei] + m_deltaVolume[ei] ) * ( 1.0 - m_porosity[ei][0] ); + real64 const dSolidVolume_dPres = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dPres[ei][0]; + real64 const dSolidVolume_dTemp = -( m_volume[ei] + m_deltaVolume[ei] ) * m_dPoro_dTemp[ei][0]; + + // initialize the solid internal energy + stack.solidEnergy = solidVolume * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dPres = dSolidVolume_dPres * m_rockInternalEnergy[ei][0]; + stack.dSolidEnergy_dTemp = solidVolume * m_dRockInternalEnergy_dTemp[ei][0] + dSolidVolume_dTemp * m_rockInternalEnergy[ei][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] kernelOp the function used to customize the kernel + */ + GEOS_HOST_DEVICE + void computeAccumulation( localIndex const ei, + StackVariables & stack ) const + { + stack.localResidual[numEqn-1] = -m_energy_n[ei]; + + Base::computeAccumulation( ei, stack, [&] () + { + // Step 1: assemble the derivatives of the mass balance equation w.r.t temperature + stack.localJacobian[0][numDof-1] = stack.poreVolume * m_dDensity_dTemp[ei][0] + stack.dPoreVolume_dTemp * m_density[ei][0]; + + // Step 2: assemble the fluid part of the accumulation term of the energy equation + real64 const fluidEnergy = stack.poreVolume * m_density[ei][0] * m_internalEnergy[ei][0]; + + real64 const dFluidEnergy_dP = stack.dPoreVolume_dPres * m_density[ei][0] * m_internalEnergy[ei][0] + + stack.poreVolume * m_dDensity_dPres[ei][0] * m_internalEnergy[ei][0] + + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dPres[ei][0]; + + real64 const dFluidEnergy_dT = stack.poreVolume * m_dDensity_dTemp[ei][0] * m_internalEnergy[ei][0] + + stack.poreVolume * m_density[ei][0] * m_dInternalEnergy_dTemp[ei][0] + + stack.dPoreVolume_dTemp * m_density[ei][0] * m_internalEnergy[ei][0]; + + // local accumulation + stack.localResidual[numEqn-1] += fluidEnergy; + + // derivatives w.r.t. pressure and temperature + stack.localJacobian[numEqn-1][0] = dFluidEnergy_dP; + stack.localJacobian[numEqn-1][numDof-1] = dFluidEnergy_dT; + } ); + + // Step 3: assemble the solid part of the accumulation term of the energy equation + stack.localResidual[numEqn-1] += stack.solidEnergy; + stack.localJacobian[numEqn-1][0] += stack.dSolidEnergy_dPres; + stack.localJacobian[numEqn-1][numDof-1] += stack.dSolidEnergy_dTemp; + } + + /** + * @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 ei, + StackVariables & stack ) const + { + // Step 1: assemble the mass balance equation + Base::complete( ei, stack ); + + // Step 2: assemble the energy equation + m_localRhs[stack.localRow + numEqn-1] += stack.localResidual[numEqn-1]; + m_localMatrix.template addToRow< serialAtomic >( stack.localRow + numEqn-1, + stack.dofIndices, + stack.localJacobian[numEqn-1], + numDof ); + } + +protected: + + /// View on derivative of fluid density w.r.t temperature + arrayView2d< real64 const > const m_dDensity_dTemp; + + /// View on derivative of porosity w.r.t temperature + arrayView2d< real64 const > const m_dPoro_dTemp; + + /// Views on fluid internal energy + arrayView2d< real64 const > const m_internalEnergy; + arrayView2d< real64 const > const m_dInternalEnergy_dPres; + arrayView2d< real64 const > const m_dInternalEnergy_dTemp; + + /// Views on rock internal energy + arrayView2d< real64 const > const m_rockInternalEnergy; + arrayView2d< real64 const > const m_dRockInternalEnergy_dTemp; + + /// View on energy + arrayView1d< real64 const > const m_energy_n; + +}; + +/** + * @class SurfaceElementAccumulationKernel + * @brief Define the interface for the assembly kernel in charge of accumulation in SurfaceElementSubRegion + */ +class SurfaceElementAccumulationKernel : public AccumulationKernel< SurfaceElementSubRegion, 2 > +{ + +public: + + using Base = AccumulationKernel< SurfaceElementSubRegion, 2 >; + + /** + * @brief Constructor + * @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 + */ + SurfaceElementAccumulationKernel( globalIndex const rankOffset, + string const dofKey, + SurfaceElementSubRegion const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + : Base( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ), + m_creationMass( subRegion.getField< fields::flow::massCreated >() ) + {} + + /** + * @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, + Base::StackVariables & stack ) const + { + Base::computeAccumulation( ei, stack ); + if( Base::m_mass_n[ei] > 1.1 * m_creationMass[ei] ) + { + stack.localResidual[0] += m_creationMass[ei] * 0.25; + } + } + +protected: + + arrayView1d< real64 const > const m_creationMass; + +}; + +/** + * @class AccumulationKernelFactory + */ +class AccumulationKernelFactory +{ +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[in] solid the solid model + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + template< typename POLICY, typename SUBREGION_TYPE > + static void + createAndLaunch( globalIndex const rankOffset, + string const dofKey, + SUBREGION_TYPE const & subRegion, + constitutive::SingleFluidBase const & fluid, + constitutive::CoupledSolidBase const & solid, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + if constexpr ( std::is_base_of_v< CellElementSubRegion, SUBREGION_TYPE > ) + { + integer constexpr NUM_DOF = 2; + AccumulationKernel< CellElementSubRegion, NUM_DOF > kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + AccumulationKernel< CellElementSubRegion, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel ); + } + else if constexpr ( std::is_base_of_v< SurfaceElementSubRegion, SUBREGION_TYPE > ) + { + SurfaceElementAccumulationKernel kernel( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + SurfaceElementAccumulationKernel::launch< POLICY >( subRegion.size(), kernel ); + } + else + { + GEOS_UNUSED_VAR( rankOffset, dofKey, subRegion, fluid, solid, localMatrix, localRhs ); + GEOS_ERROR( "Unsupported subregion type: " << typeid(SUBREGION_TYPE).name() ); + } + } + +}; + +} // namespace thermalSinglePhaseBaseKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALACCUMULATIONKERNELS_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp new file mode 100644 index 00000000000..8e6bc1ba8fe --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalDirichletFluxComputeKernel.hpp @@ -0,0 +1,393 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 Total, S.A + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ThermalDirichletFluxComputeKernel.hpp + */ + +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP + +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" + +#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp" +#include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" + +namespace geos +{ + +namespace thermalSinglePhaseFVMKernels +{ + +/******************************** DirichletFluxComputeKernel ********************************/ + +/** + * @class DirichletFluxComputeKernel + * @tparam FLUIDWRAPPER the type of the fluid wrapper + * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms + */ +template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > +class DirichletFluxComputeKernel : public singlePhaseFVMKernels::DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER > +{ +public: + +/** + * @brief The type for element-based data. Consists entirely of ArrayView's. + * + * Can be converted from ElementRegionManager::ElementViewConstAccessor + * by calling .toView() or .toViewConst() on an accessor instance + */ + template< typename VIEWTYPE > + using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; + + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; + using DofNumberAccessor = AbstractBase::DofNumberAccessor; + using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; + using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; + using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; + + using AbstractBase::m_dt; + using AbstractBase::m_rankOffset; + using AbstractBase::m_dofNumber; + using AbstractBase::m_ghostRank; + using AbstractBase::m_gravCoef; + using AbstractBase::m_mob; + using AbstractBase::m_pres; + using AbstractBase::m_permeability; + using AbstractBase::m_dPerm_dPres; + + using AbstractBase::m_localMatrix; + using AbstractBase::m_localRhs; + + using Base = singlePhaseFVMKernels::DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER >; + using Base::numDof; + using Base::numEqn; + using Base::m_stencilWrapper; + using Base::m_seri; + using Base::m_sesri; + using Base::m_sei; + using Base::m_facePres; + using Base::m_faceGravCoef; + + using ThermalSinglePhaseFlowAccessors = + StencilAccessors< fields::flow::temperature, + fields::flow::dMobility_dTemperature >; + + using ThermalSinglePhaseFluidAccessors = + StencilMaterialAccessors< constitutive::SingleFluidBase, + fields::singlefluid::dDensity_dTemperature, + fields::singlefluid::enthalpy, + fields::singlefluid::dEnthalpy_dPressure, + fields::singlefluid::dEnthalpy_dTemperature >; + + using ThermalConductivityAccessors = + StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase, + fields::thermalconductivity::effectiveConductivity, + fields::thermalconductivity::dEffectiveConductivity_dT >; + + /** + * @brief Constructor for the kernel interface + * @param[in] rankOffset the offset of the MPI rank + * @param[in] faceManager the face manager + * @param[in] stencilWrapper reference to the stencil wrapper + * @param[in] fluidWrapper reference to the fluid wrapper + * @param[in] dofNumberAccessor the degree of freedom number accessor + * @param[in] singlePhaseFlowAccessors the single phase flow accessor + * @param[in] thermalSinglePhaseFlowAccessors the thermal single phase flow accessor + * @param[in] singlePhaseFluidAccessors the single phase fluid accessor + * @param[in] thermalSinglePhaseFluidAccessors the thermal single phase fluid accessor + * @param[in] permeabilityAccessors the permeability accessor + * @param[in] thermalConductivityAccessors the thermal conductivity accessor + * @param[in] dt the time step size + * @param[inout] localMatrix the local CRS matrix + * @param[inout] localRhs the local right-hand side vector + */ + DirichletFluxComputeKernel( globalIndex const rankOffset, + FaceManager const & faceManager, + BoundaryStencilWrapper const & stencilWrapper, + FLUIDWRAPPER const & fluidWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + + : Base( rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + singlePhaseFluidAccessors, + permeabilityAccessors, + dt, + localMatrix, + localRhs ), + m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ), + m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), + m_dMob_dTemp( thermalSinglePhaseFlowAccessors.get( fields::flow::dMobility_dTemperature {} ) ), + m_dDens_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dDensity_dTemperature {} ) ), + m_enthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ), + m_dEnthalpy_dPres( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dPressure {} ) ), + m_dEnthalpy_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dTemperature {} ) ), + m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ), + m_dThermalCond_dT( thermalConductivityAccessors.get( fields::thermalconductivity::dEffectiveConductivity_dT {} ) ) + {} + + + /** + * @struct StackVariables + * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack + */ + struct StackVariables : Base::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, + localIndex numElems ): + Base::StackVariables( size, + numElems ) + {} + + using Base::StackVariables::localFlux; + using Base::StackVariables::localFluxJacobian; + using Base::StackVariables::dofColIndices; + using Base::StackVariables::transmissibility; + + /// Energy fluxes and derivatives wrt pressure and temperature + real64 energyFlux = 0.0; + real64 dEnergyFlux_dP = 0.0; + real64 dEnergyFlux_dT = 0.0; + }; + + /** + * @brief Compute the local Dirichlet face 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] iconn the connection index + * @param[inout] stack the stack variables + * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes + */ + GEOS_HOST_DEVICE + void computeFlux( localIndex const iconn, + StackVariables & stack ) const + { + Base::computeFlux( iconn, stack, [&] ( localIndex const er, + localIndex const esr, + localIndex const ei, + localIndex const kf, + real64 const & f, + real64 const & dF_dP, + real64 const & mobility_up, + real64 const & dMobility_dP_up ) + { + + // Compute the derivatives of the density wrt temperature + + real64 const dDens_dT = 0.5 * m_dDens_dTemp[er][esr][ei][0]; + + // Compute the derivatives of the phase potential difference wrt temperature + + real64 const dF_dT = -stack.transmissibility * dDens_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); + + // Compute the (upwinded) energy flux + + real64 const flux = mobility_up * f; + real64 const enthalpy = m_enthalpy[er][esr][ei][0]; + stack.energyFlux += flux * enthalpy; + + // Compute the derivatives of the (upwinded) energy flux wrt pressure and temperature + + if( f >= 0 ) // the element is upstream + { + real64 const dFlux_dP = mobility_up * dF_dP + dMobility_dP_up * f; + real64 const dFlux_dT = mobility_up * dF_dT + m_dMob_dTemp[er][esr][ei] * f; + + stack.dEnergyFlux_dP += dFlux_dP * enthalpy + flux * m_dEnthalpy_dPres[er][esr][ei][0]; + stack.dEnergyFlux_dT += dFlux_dT * enthalpy + flux * m_dEnthalpy_dTemp[er][esr][ei][0]; + } + else + { + real64 const dFlux_dP = mobility_up * dF_dP; + real64 const dFlux_dT = mobility_up * dF_dT; + + stack.dEnergyFlux_dP += dFlux_dP * enthalpy; + stack.dEnergyFlux_dT += dFlux_dT * enthalpy; + } + + // Contribution of energy conduction through the solid phase + real64 thermalTrans = 0.0; + real64 dThermalTrans_dThermalCond[3]{}; + m_stencilWrapper.computeWeights( iconn, + m_thermalConductivity, + thermalTrans, + dThermalTrans_dThermalCond ); + + real64 const dThermalTrans_dT = LvArray::tensorOps::AiBi< 3 >( dThermalTrans_dThermalCond, m_dThermalCond_dT[er][esr][ei][0] ); + + real64 const deltaT = m_temp[er][esr][ei] - m_faceTemp[kf]; + stack.energyFlux += thermalTrans * deltaT; + stack.dEnergyFlux_dT += thermalTrans + dThermalTrans_dT * deltaT; + + // Add energyFlux and its derivatives to localFlux and localFluxJacobian + integer const localRowIndexEnergy = numEqn - 1; + stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; + + stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; + stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; + } ); + + } + + /** + * @brief Performs the complete phase for the kernel. + * @param[in] iconn the connection index + * @param[inout] stack the stack variables + */ + GEOS_HOST_DEVICE + void complete( localIndex const iconn, + StackVariables & stack ) const + { + Base::complete( iconn, stack, [&] ( localIndex const localRow ) + { + RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - 1], stack.localFlux[numEqn-1] ); + + AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > + ( localRow + numEqn - 1, + stack.dofColIndices, + stack.localFluxJacobian[numEqn-1], + numDof ); + } ); + } + +protected: + + /// Views on temperature + ElementViewConst< arrayView1d< real64 const > > const m_temp; + + /// Views on face temperature + arrayView1d< real64 const > const m_faceTemp; + + /// Views on derivatives of fluid mobilities + ElementViewConst< arrayView1d< real64 const > > const m_dMob_dTemp; + + /// Views on derivatives of fluid densities + ElementViewConst< arrayView2d< real64 const > > const m_dDens_dTemp; + + /// Views on enthalpies + ElementViewConst< arrayView2d< real64 const > > const m_enthalpy; + ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dPres; + ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dTemp; + + /// View on thermal conductivity + ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity; + + /// View on derivatives of thermal conductivity w.r.t. temperature + ElementViewConst< arrayView3d< real64 const > > m_dThermalCond_dT; + +}; + +/** + * @class DirichletFluxComputeKernelFactory + */ +class DirichletFluxComputeKernelFactory +{ +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 string to get the element degrees of freedom numbers + * @param[in] solverName name of the solver (to name accessors) + * @param[in] faceManager reference to the face manager + * @param[in] elemManager reference to the element region manager + * @param[in] stencilWrapper reference to the boundary stencil wrapper + * @param[in] fluidBase the single phase fluid constitutive model + * @param[in] dt time step size + * @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, + string const & solverName, + FaceManager const & faceManager, + ElementRegionManager const & elemManager, + BoundaryStencilWrapper const & stencilWrapper, + constitutive::SingleFluidBase & fluidBase, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) + { + constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) + { + using FluidType = TYPEOFREF( fluid ); + typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); + + integer constexpr NUM_DOF = 2; + integer constexpr NUM_EQN = 2; + + using kernelType = DirichletFluxComputeKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; + + ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = + elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); + + dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); + + typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); + typename kernelType::ThermalSinglePhaseFlowAccessors thermalSinglePhaseFlowAccessors( elemManager, solverName ); + typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); + typename kernelType::ThermalSinglePhaseFluidAccessors thermalSinglePhaseFluidAccessors( elemManager, solverName ); + typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); + typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); + + kernelType kernel( rankOffset, + faceManager, + stencilWrapper, + fluidWrapper, + dofNumberAccessor, + singlePhaseFlowAccessors, + thermalSinglePhaseFlowAccessors, + singlePhaseFluidAccessors, + thermalSinglePhaseFluidAccessors, + permeabilityAccessors, + thermalConductivityAccessors, + dt, + localMatrix, + localRhs ); + + kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); + } ); + } + +}; + +} // namespace thermalSinglePhaseFVMKernels + +} // namespace geos + +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp similarity index 52% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp index ec28bf14e5b..cba7c440e09 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/ThermalSinglePhaseFVMKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp @@ -14,33 +14,32 @@ */ /** - * @file ThermalSinglePhaseFVMKernels.hpp + * @file ThermalFluxComputeKernel.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEFVMKERNELS_HPP -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEFVMKERNELS_HPP +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" #include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp" #include "constitutive/thermalConductivity/ThermalConductivityFields.hpp" -#include "constitutive/thermalConductivity/SinglePhaseThermalConductivityFields.hpp" namespace geos { namespace thermalSinglePhaseFVMKernels { -/******************************** FaceBasedAssemblyKernel ********************************/ +/******************************** FluxComputeKernel ********************************/ /** - * @class FaceBasedAssemblyKernel + * @class FluxComputeKernel * @tparam NUM_DOF number of degrees of freedom * @tparam STENCILWRAPPER the type of the stencil wrapper * @brief Define the interface for the assembly kernel in charge of flux terms */ template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER > -class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER > +class FluxComputeKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER > { public: @@ -53,7 +52,7 @@ class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyK template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; @@ -66,7 +65,7 @@ class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyK using AbstractBase::m_mob; using AbstractBase::m_dens; - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; using Base::numDof; using Base::numEqn; using Base::maxNumElems; @@ -109,18 +108,18 @@ class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyK * @param[inout] localMatrix the local CRS matrix * @param[inout] localRhs the local right-hand side vector */ - FaceBasedAssemblyKernel( globalIndex const rankOffset, - STENCILWRAPPER const & stencilWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) + FluxComputeKernel( globalIndex const rankOffset, + STENCILWRAPPER const & stencilWrapper, + DofNumberAccessor const & dofNumberAccessor, + SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, + ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, + SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, + ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, + PermeabilityAccessors const & permeabilityAccessors, + ThermalConductivityAccessors const & thermalConductivityAccessors, + real64 const & dt, + CRSMatrixView< real64, globalIndex const > const & localMatrix, + arrayView1d< real64 > const & localRhs ) : Base( rankOffset, stencilWrapper, dofNumberAccessor, @@ -433,9 +432,9 @@ class FaceBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyK }; /** - * @class FaceBasedAssemblyKernelFactory + * @class FluxComputeKernelFactory */ -class FaceBasedAssemblyKernelFactory +class FluxComputeKernelFactory { public: @@ -470,7 +469,7 @@ class FaceBasedAssemblyKernelFactory elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - using KernelType = FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; + using KernelType = FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >; typename KernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName ); typename KernelType::ThermalSinglePhaseFlowAccessors thermalFlowAccessors( elemManager, solverName ); typename KernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName ); @@ -486,364 +485,8 @@ class FaceBasedAssemblyKernelFactory } }; -/******************************** DirichletFaceBasedAssemblyKernel ********************************/ - -/** - * @class DirichFaceBasedAssemblyKernel - * @tparam FLUIDWRAPPER the type of the fluid wrapper - * @brief Define the interface for the assembly kernel in charge of Dirichlet face flux terms - */ -template< integer NUM_EQN, integer NUM_DOF, typename FLUIDWRAPPER > -class DirichletFaceBasedAssemblyKernel : public singlePhaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER > -{ -public: - -/** - * @brief The type for element-based data. Consists entirely of ArrayView's. - * - * Can be converted from ElementRegionManager::ElementViewConstAccessor - * by calling .toView() or .toViewConst() on an accessor instance - */ - template< typename VIEWTYPE > - using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; - using DofNumberAccessor = AbstractBase::DofNumberAccessor; - using PermeabilityAccessors = AbstractBase::PermeabilityAccessors; - using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; - using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; - - using AbstractBase::m_dt; - using AbstractBase::m_rankOffset; - using AbstractBase::m_dofNumber; - using AbstractBase::m_ghostRank; - using AbstractBase::m_gravCoef; - using AbstractBase::m_mob; - using AbstractBase::m_pres; - using AbstractBase::m_permeability; - using AbstractBase::m_dPerm_dPres; - - using AbstractBase::m_localMatrix; - using AbstractBase::m_localRhs; - - using Base = singlePhaseFVMKernels::DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, FLUIDWRAPPER >; - using Base::numDof; - using Base::numEqn; - using Base::m_stencilWrapper; - using Base::m_seri; - using Base::m_sesri; - using Base::m_sei; - using Base::m_facePres; - using Base::m_faceGravCoef; - - using ThermalSinglePhaseFlowAccessors = - StencilAccessors< fields::flow::temperature, - fields::flow::dMobility_dTemperature >; - - using ThermalSinglePhaseFluidAccessors = - StencilMaterialAccessors< constitutive::SingleFluidBase, - fields::singlefluid::dDensity_dTemperature, - fields::singlefluid::enthalpy, - fields::singlefluid::dEnthalpy_dPressure, - fields::singlefluid::dEnthalpy_dTemperature >; - - using ThermalConductivityAccessors = - StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase, - fields::thermalconductivity::effectiveConductivity, - fields::thermalconductivity::dEffectiveConductivity_dT >; - - /** - * @brief Constructor for the kernel interface - * @param[in] rankOffset the offset of the MPI rank - * @param[in] faceManager the face manager - * @param[in] stencilWrapper reference to the stencil wrapper - * @param[in] fluidWrapper reference to the fluid wrapper - * @param[in] dofNumberAccessor the degree of freedom number accessor - * @param[in] singlePhaseFlowAccessors the single phase flow accessor - * @param[in] thermalSinglePhaseFlowAccessors the thermal single phase flow accessor - * @param[in] singlePhaseFluidAccessors the single phase fluid accessor - * @param[in] thermalSinglePhaseFluidAccessors the thermal single phase fluid accessor - * @param[in] permeabilityAccessors the permeability accessor - * @param[in] thermalConductivityAccessors the thermal conductivity accessor - * @param[in] dt the time step size - * @param[inout] localMatrix the local CRS matrix - * @param[inout] localRhs the local right-hand side vector - */ - DirichletFaceBasedAssemblyKernel( globalIndex const rankOffset, - FaceManager const & faceManager, - BoundaryStencilWrapper const & stencilWrapper, - FLUIDWRAPPER const & fluidWrapper, - DofNumberAccessor const & dofNumberAccessor, - SinglePhaseFlowAccessors const & singlePhaseFlowAccessors, - ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors, - SinglePhaseFluidAccessors const & singlePhaseFluidAccessors, - ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors, - PermeabilityAccessors const & permeabilityAccessors, - ThermalConductivityAccessors const & thermalConductivityAccessors, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - - : Base( rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - singlePhaseFluidAccessors, - permeabilityAccessors, - dt, - localMatrix, - localRhs ), - m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ), - m_faceTemp( faceManager.getField< fields::flow::faceTemperature >() ), - m_dMob_dTemp( thermalSinglePhaseFlowAccessors.get( fields::flow::dMobility_dTemperature {} ) ), - m_dDens_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dDensity_dTemperature {} ) ), - m_enthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ), - m_dEnthalpy_dPres( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dPressure {} ) ), - m_dEnthalpy_dTemp( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy_dTemperature {} ) ), - m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ), - m_dThermalCond_dT( thermalConductivityAccessors.get( fields::thermalconductivity::dEffectiveConductivity_dT {} ) ) - {} - - - /** - * @struct StackVariables - * @brief Kernel variables (dof numbers, jacobian and residual) located on the stack - */ - struct StackVariables : Base::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, - localIndex numElems ): - Base::StackVariables( size, - numElems ) - {} - - using Base::StackVariables::localFlux; - using Base::StackVariables::localFluxJacobian; - using Base::StackVariables::dofColIndices; - using Base::StackVariables::transmissibility; - - /// Energy fluxes and derivatives wrt pressure and temperature - real64 energyFlux = 0.0; - real64 dEnergyFlux_dP = 0.0; - real64 dEnergyFlux_dT = 0.0; - }; - - /** - * @brief Compute the local Dirichlet face 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] iconn the connection index - * @param[inout] stack the stack variables - * @param[in] compFluxKernelOp the function used to customize the computation of the component fluxes - */ - GEOS_HOST_DEVICE - void computeFlux( localIndex const iconn, - StackVariables & stack ) const - { - Base::computeFlux( iconn, stack, [&] ( localIndex const er, - localIndex const esr, - localIndex const ei, - localIndex const kf, - real64 const & f, - real64 const & dF_dP, - real64 const & mobility_up, - real64 const & dMobility_dP_up ) - { - - // Compute the derivatives of the density wrt temperature - - real64 const dDens_dT = 0.5 * m_dDens_dTemp[er][esr][ei][0]; - - // Compute the derivatives of the phase potential difference wrt temperature - - real64 const dF_dT = -stack.transmissibility * dDens_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] ); - - // Compute the (upwinded) energy flux - - real64 const flux = mobility_up * f; - real64 const enthalpy = m_enthalpy[er][esr][ei][0]; - stack.energyFlux += flux * enthalpy; - - // Compute the derivatives of the (upwinded) energy flux wrt pressure and temperature - - if( f >= 0 ) // the element is upstream - { - real64 const dFlux_dP = mobility_up * dF_dP + dMobility_dP_up * f; - real64 const dFlux_dT = mobility_up * dF_dT + m_dMob_dTemp[er][esr][ei] * f; - - stack.dEnergyFlux_dP += dFlux_dP * enthalpy + flux * m_dEnthalpy_dPres[er][esr][ei][0]; - stack.dEnergyFlux_dT += dFlux_dT * enthalpy + flux * m_dEnthalpy_dTemp[er][esr][ei][0]; - } - else - { - real64 const dFlux_dP = mobility_up * dF_dP; - real64 const dFlux_dT = mobility_up * dF_dT; - - stack.dEnergyFlux_dP += dFlux_dP * enthalpy; - stack.dEnergyFlux_dT += dFlux_dT * enthalpy; - } - - // Contribution of energy conduction through the solid phase - real64 thermalTrans = 0.0; - real64 dThermalTrans_dThermalCond[3]{}; - m_stencilWrapper.computeWeights( iconn, - m_thermalConductivity, - thermalTrans, - dThermalTrans_dThermalCond ); - - real64 const dThermalTrans_dT = LvArray::tensorOps::AiBi< 3 >( dThermalTrans_dThermalCond, m_dThermalCond_dT[er][esr][ei][0] ); - - real64 const deltaT = m_temp[er][esr][ei] - m_faceTemp[kf]; - stack.energyFlux += thermalTrans * deltaT; - stack.dEnergyFlux_dT += thermalTrans + dThermalTrans_dT * deltaT; - - // Add energyFlux and its derivatives to localFlux and localFluxJacobian - integer const localRowIndexEnergy = numEqn - 1; - stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux; - - stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP; - stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT; - } ); - - } - - /** - * @brief Performs the complete phase for the kernel. - * @param[in] iconn the connection index - * @param[inout] stack the stack variables - */ - GEOS_HOST_DEVICE - void complete( localIndex const iconn, - StackVariables & stack ) const - { - Base::complete( iconn, stack, [&] ( localIndex const localRow ) - { - RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn - 1], stack.localFlux[numEqn-1] ); - - AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic > - ( localRow + numEqn - 1, - stack.dofColIndices, - stack.localFluxJacobian[numEqn-1], - numDof ); - } ); - } - -protected: - - /// Views on temperature - ElementViewConst< arrayView1d< real64 const > > const m_temp; - - /// Views on face temperature - arrayView1d< real64 const > const m_faceTemp; - - /// Views on derivatives of fluid mobilities - ElementViewConst< arrayView1d< real64 const > > const m_dMob_dTemp; - - /// Views on derivatives of fluid densities - ElementViewConst< arrayView2d< real64 const > > const m_dDens_dTemp; - - /// Views on enthalpies - ElementViewConst< arrayView2d< real64 const > > const m_enthalpy; - ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dPres; - ElementViewConst< arrayView2d< real64 const > > const m_dEnthalpy_dTemp; - - /// View on thermal conductivity - ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity; - - /// View on derivatives of thermal conductivity w.r.t. temperature - ElementViewConst< arrayView3d< real64 const > > m_dThermalCond_dT; - -}; - - -/** - * @class DirichletFaceBasedAssemblyKernelFactory - */ -class DirichletFaceBasedAssemblyKernelFactory -{ -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 string to get the element degrees of freedom numbers - * @param[in] solverName name of the solver (to name accessors) - * @param[in] faceManager reference to the face manager - * @param[in] elemManager reference to the element region manager - * @param[in] stencilWrapper reference to the boundary stencil wrapper - * @param[in] fluidBase the single phase fluid constitutive model - * @param[in] dt time step size - * @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, - string const & solverName, - FaceManager const & faceManager, - ElementRegionManager const & elemManager, - BoundaryStencilWrapper const & stencilWrapper, - constitutive::SingleFluidBase & fluidBase, - real64 const & dt, - CRSMatrixView< real64, globalIndex const > const & localMatrix, - arrayView1d< real64 > const & localRhs ) - { - constitutiveUpdatePassThru( fluidBase, [&]( auto & fluid ) - { - using FluidType = TYPEOFREF( fluid ); - typename FluidType::KernelWrapper fluidWrapper = fluid.createKernelWrapper(); - - integer constexpr NUM_DOF = 2; - integer constexpr NUM_EQN = 2; - - using kernelType = DirichletFaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, typename FluidType::KernelWrapper >; - - ElementRegionManager::ElementViewAccessor< arrayView1d< globalIndex const > > dofNumberAccessor = - elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey ); - - dofNumberAccessor.setName( solverName + "/accessors/" + dofKey ); - - typename kernelType::SinglePhaseFlowAccessors singlePhaseFlowAccessors( elemManager, solverName ); - typename kernelType::ThermalSinglePhaseFlowAccessors thermalSinglePhaseFlowAccessors( elemManager, solverName ); - typename kernelType::SinglePhaseFluidAccessors singlePhaseFluidAccessors( elemManager, solverName ); - typename kernelType::ThermalSinglePhaseFluidAccessors thermalSinglePhaseFluidAccessors( elemManager, solverName ); - typename kernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName ); - typename kernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName ); - - kernelType kernel( rankOffset, - faceManager, - stencilWrapper, - fluidWrapper, - dofNumberAccessor, - singlePhaseFlowAccessors, - thermalSinglePhaseFlowAccessors, - singlePhaseFluidAccessors, - thermalSinglePhaseFluidAccessors, - permeabilityAccessors, - thermalConductivityAccessors, - dt, - localMatrix, - localRhs ); - - kernelType::template launch< POLICY >( stencilWrapper.size(), kernel ); - } ); - } - -}; - } // namespace thermalSinglePhaseFVMKernels } // namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_THERMALSINGLEPHASEFVMKERNELS_HPP +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp similarity index 90% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantBaseKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp index 6f3395bad2e..9e36375b45c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantBaseKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp @@ -16,8 +16,8 @@ /** * @file SinglePhaseProppantBaseKernels.hpp */ -#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEPROPPANTBASEKERNELS_HPP_ -#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEPROPPANTBASEKERNELS_HPP_ +#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_PROPPANTBASEKERNELS_HPP_ +#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_PROPPANTBASEKERNELS_HPP_ #include "common/DataTypes.hpp" #include "common/GEOS_RAJA_Interface.hpp" @@ -61,4 +61,4 @@ struct FluidUpdateKernel } //namespace geos -#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASEPROPPANTBASEKERNELS_HPP_ +#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_PROPPANTBASEKERNELS_HPP_ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantFluxKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp similarity index 98% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantFluxKernels.cpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp index 193fc117989..22dec62d10f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantFluxKernels.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp @@ -14,12 +14,12 @@ */ /** - * @file singlePhaseProppantFluxKernels.cpp + * @file ProppantFluxKernels.cpp */ -#include "SinglePhaseProppantFluxKernels.hpp" +#include "ProppantFluxKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" namespace geos { @@ -27,7 +27,7 @@ namespace geos namespace singlePhaseProppantFluxKernels { -using namespace fluxKernelsHelper; +using namespace singlePhaseFluxKernelsHelper; void FaceElementFluxKernel:: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.hpp similarity index 100% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/SinglePhaseProppantFluxKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.hpp diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 14e891c87ae..95f59c179ec 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -42,8 +42,16 @@ #include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp" #include "physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/ThermalCompositionalMultiphaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp" #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" @@ -1385,7 +1393,7 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, auto const subRegionData = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxRelativeTempChange, @@ -1404,7 +1412,7 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, localSolution, temperatureOffset ) : isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxCompFracChange, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 9834ceb56ee..4671f593665 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -36,6 +36,8 @@ #include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp" #include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" namespace geos @@ -312,7 +314,7 @@ void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid ) { typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper(); - thermalSinglePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); + singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp index 422d4d2f75c..1ca6ebac997 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp @@ -33,7 +33,10 @@ #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/StencilAccessors.hpp" -#include "physicsSolvers/fluidFlow/kernels/IsothermalCompositionalMultiphaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp" #include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellControls.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" @@ -731,12 +734,12 @@ class ResidualNormKernelFactory }; -/******************************** ScalingForSystemSolutionKernel ********************************/ +/******************************** SolutionScalingKernel ********************************/ /** - * @class ScalingForSystemSolutionKernelFactory + * @class SolutionScalingKernelFactory */ -class ScalingForSystemSolutionKernelFactory +class SolutionScalingKernelFactory { public: @@ -754,7 +757,7 @@ class ScalingForSystemSolutionKernelFactory * @param[in] localSolution the Newton update */ template< typename POLICY > - static isothermalCompositionalMultiphaseBaseKernels::ScalingForSystemSolutionKernel::StackVariables + static isothermalCompositionalMultiphaseBaseKernels::SolutionScalingKernel::StackVariables createAndLaunch( real64 const maxRelativePresChange, real64 const maxAbsolutePresChange, real64 const maxCompFracChange, @@ -774,10 +777,10 @@ class ScalingForSystemSolutionKernelFactory arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >(); isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, maxRelativeCompDensChange, rankOffset, - numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); + SolutionScalingKernel kernel( maxRelativePresChange, maxAbsolutePresChange, maxCompFracChange, maxRelativeCompDensChange, rankOffset, + numComp, dofKey, subRegion, localSolution, pressure, compDens, pressureScalingFactor, compDensScalingFactor ); return isothermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernel:: + SolutionScalingKernel:: launch< POLICY >( subRegion.size(), kernel ); } @@ -879,7 +882,7 @@ class ElementBasedAssemblyKernel constitutive::MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags ) : m_numPhases( numPhases ), m_isProducer( isProducer ), m_rankOffset( rankOffset ), @@ -1192,7 +1195,7 @@ class ElementBasedAssemblyKernel } } - if( m_kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) + if( m_kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ) ) { // apply equation/variable change transformation to the component mass balance equations real64 work[numComp + 1 + IS_THERMAL]{}; @@ -1301,7 +1304,7 @@ class ElementBasedAssemblyKernel /// View on the local RHS arrayView1d< real64 > const m_localRhs; - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const m_kernelFlags; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const m_kernelFlags; }; @@ -1342,9 +1345,9 @@ class ElementBasedAssemblyKernelFactory integer constexpr istherm = IS_THERMAL(); - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); ElementBasedAssemblyKernel< NUM_COMP, istherm > kernel( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); @@ -1407,7 +1410,7 @@ class FaceBasedAssemblyKernel WellElementSubRegion const & subRegion, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) : m_dt( dt ), m_rankOffset( rankOffset ), @@ -1418,7 +1421,7 @@ class FaceBasedAssemblyKernel m_dWellElemCompFrac_dCompDens ( subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >() ), m_localMatrix( localMatrix ), m_localRhs ( localRhs ), - m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ), + m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ) ), m_isProducer ( wellControls.isProducer() ), m_injection ( wellControls.getInjectionStream() ) {} @@ -1898,9 +1901,9 @@ class FaceBasedAssemblyKernelFactory integer constexpr NUM_COMP = NC(); - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); using kernelType = FaceBasedAssemblyKernel< NUM_COMP, 0 >; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp index bbef327079f..3c3b9a2b9d6 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp @@ -482,7 +482,7 @@ class ElementBasedAssemblyKernel : public compositionalMultiphaseWellKernels::El MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > const kernelFlags ) + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags ) : Base( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ), m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n()), m_phaseInternalEnergy( fluid.phaseInternalEnergy()), @@ -650,9 +650,9 @@ class ElementBasedAssemblyKernelFactory localIndex constexpr NUM_COMP = NC(); - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); ElementBasedAssemblyKernel< NUM_COMP > kernel( numPhases, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ); @@ -722,7 +722,7 @@ class FaceBasedAssemblyKernel : public compositionalMultiphaseWellKernels::FaceB MultiFluidBase const & fluid, CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) : Base( dt , rankOffset , wellDofKey @@ -1101,9 +1101,9 @@ class FaceBasedAssemblyKernelFactory integer constexpr NUM_COMP = NC(); - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); using kernelType = FaceBasedAssemblyKernel< NUM_COMP >; diff --git a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp index 9899606e970..6aba3bc91f3 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/CoupledReservoirAndWellKernels.hpp @@ -94,7 +94,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel CRSMatrixView< real64, globalIndex const > const & localMatrix, bool const & detectCrossflow, integer & numCrossFlowPerforations, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) : m_dt( dt ), m_numPhases ( fluid.numFluidPhases()), @@ -111,7 +111,7 @@ class IsothermalCompositionalMultiPhaseFluxKernel m_localMatrix( localMatrix ), m_detectCrossflow( detectCrossflow ), m_numCrossFlowPerforations( numCrossFlowPerforations ), - m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ) ) + m_useTotalMassEquation ( kernelFlags.isSet( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ) ) { } @@ -317,9 +317,9 @@ class IsothermalCompositionalMultiPhaseFluxKernelFactory integer constexpr NUM_COMP = NC(); - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); using kernelType = IsothermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 0 >; @@ -397,7 +397,7 @@ class ThermalCompositionalMultiPhaseFluxKernel : public IsothermalCompositionalM CRSMatrixView< real64, globalIndex const > const & localMatrix, bool const & detectCrossflow, integer & numCrossFlowPerforations, - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags ) + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags ) : Base( dt, rankOffset, wellDofKey, @@ -570,9 +570,9 @@ class ThermalCompositionalMultiPhaseFluxKernelFactory integer constexpr NUM_COMP = NC(); - BitFlags< isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags > kernelFlags; + BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags; if( useTotalMassEquation ) - kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::ElementBasedAssemblyKernelFlags::TotalMassEquation ); + kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation ); using kernelType = ThermalCompositionalMultiPhaseFluxKernel< NUM_COMP, 1 >; diff --git a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp index 44f214e2de8..d3322e839ff 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.cpp @@ -21,6 +21,7 @@ #include "constitutive/contact/HydraulicApertureRelationSelector.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" #include "physicsSolvers/multiphysics/HydrofractureSolverKernels.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" #include "physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp" @@ -29,7 +30,7 @@ #include "physicsSolvers/surfaceGeneration/LogLevelsInfo.hpp" #include "dataRepository/LogLevelsInfo.hpp" #include "mesh/MeshFields.hpp" -#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" namespace geos { @@ -211,7 +212,6 @@ real64 HydrofractureSolver< POROMECHANICS_SOLVER >::fullyCoupledSolverStep( real // currently the only method is implicit time integration dtReturn = nonlinearImplicitStep( time_n, dt, cycleNumber, domain ); - if( !this->m_performStressInitialization && m_surfaceGenerator->solverStep( time_n, dt, cycleNumber, domain ) > 0 ) { locallyFractured = 1; @@ -905,6 +905,13 @@ void HydrofractureSolver< POROMECHANICS_SOLVER >::implicitStepComplete( real64 c } } +template< typename POROMECHANICS_SOLVER > +void HydrofractureSolver< POROMECHANICS_SOLVER >::resetStateToBeginningOfStep( DomainPartition & domain ) +{ + Base::resetStateToBeginningOfStep( domain ); + updateState( domain ); +} + template< typename POROMECHANICS_SOLVER > real64 HydrofractureSolver< POROMECHANICS_SOLVER >::setNextDt( real64 const & currentDt, DomainPartition & domain ) diff --git a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp index d3e08989f95..8ea2ddc1d8b 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/HydrofractureSolver.hpp @@ -57,6 +57,7 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER using Base::flowSolver; using Base::solidMechanicsSolver; using Base::assembleElementBasedTerms; + using Base::resetStateToBeginningOfStep; /** @@ -130,6 +131,8 @@ class HydrofractureSolver : public POROMECHANICS_SOLVER real64 const & dt, DomainPartition & domain ) override final; + virtual void resetStateToBeginningOfStep( DomainPartition & domain ) override final; + /**@}*/ void updateHydraulicApertureAndFracturePermeability( DomainPartition & domain ); diff --git a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp index aaa5864dd0d..4d1e0114728 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.cpp @@ -219,37 +219,6 @@ void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::assembleElementBa this->solidMechanicsSolver()->getMaxForce() = LvArray::math::max( mechanicsMaxForce, poromechanicsMaxForce ); } -template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > -void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::updateState( DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - - real64 maxDeltaPhaseVolFrac = 0.0; - this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - ElementRegionManager & elemManager = mesh.getElemManager(); - elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, - [&]( localIndex const, - CellElementSubRegion & subRegion ) - { - real64 const deltaPhaseVolFrac = this->flowSolver()->updateFluidState( subRegion ); - maxDeltaPhaseVolFrac = LvArray::math::max( maxDeltaPhaseVolFrac, deltaPhaseVolFrac ); - if( this->m_isThermal ) - { - this->flowSolver()->updateSolidInternalEnergyModel( subRegion ); - } - } ); - } ); - - maxDeltaPhaseVolFrac = MpiWrapper::max( maxDeltaPhaseVolFrac ); - - GEOS_LOG_LEVEL_INFO_RANK_0( logInfo::Solution, - GEOS_FMT( " {}: Max phase volume fraction change = {}", - this->getName(), GEOS_FMT( "{:.{}f}", maxDeltaPhaseVolFrac, 4 ) ) ); -} - template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > void MultiphasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::initializePostInitialConditionsPreSubGroups() { diff --git a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp index 7cce059248a..9251d86dac1 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/MultiphasePoromechanics.hpp @@ -101,8 +101,6 @@ class MultiphasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHANI CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); - virtual void updateState( DomainPartition & domain ) override; - /**@}*/ protected: diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp index 53dee4f6bab..46233badae0 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.cpp @@ -291,31 +291,6 @@ void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::createPreconditi } } -template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > -void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::updateState( DomainPartition & domain ) -{ - GEOS_MARK_FUNCTION; - - this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - arrayView1d< string const > const & regionNames ) - { - - ElementRegionManager & elemManager = mesh.getElemManager(); - - elemManager.forElementSubRegions< CellElementSubRegion >( regionNames, - [&]( localIndex const, - CellElementSubRegion & subRegion ) - { - this->flowSolver()->updateFluidState( subRegion ); - if( this->m_isThermal ) - { - this->flowSolver()->updateSolidInternalEnergyModel( subRegion ); - } - } ); - } ); -} - template< typename FLOW_SOLVER, typename MECHANICS_SOLVER > void SinglePhasePoromechanics< FLOW_SOLVER, MECHANICS_SOLVER >::updateBulkDensity( ElementSubRegionBase & subRegion ) { diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp index dd9110fb79b..f311b786c38 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanics.hpp @@ -107,8 +107,6 @@ class SinglePhasePoromechanics : public PoromechanicsSolver< FLOW_SOLVER, MECHAN CRSMatrixView< real64, globalIndex const > const & localMatrix, arrayView1d< real64 > const & localRhs ); - virtual void updateState( DomainPartition & domain ) override; - /**@}*/ struct viewKeyStruct : Base::viewKeyStruct diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp index 48deed2cf6a..77bbc8fdeab 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsConformingFractures.cpp @@ -22,15 +22,16 @@ #include "dataRepository/LogLevelsInfo.hpp" #include "constitutive/solid/PorousSolid.hpp" #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp" +#include "constitutive/contact/HydraulicApertureRelationSelector.hpp" #include "linearAlgebra/solvers/BlockPreconditioner.hpp" #include "linearAlgebra/solvers/SeparateComponentPreconditioner.hpp" -#include "constitutive/contact/HydraulicApertureRelationSelector.hpp" #include "physicsSolvers/fluidFlow/SinglePhaseBase.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanics.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanics.hpp" #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsFractures.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" namespace geos { diff --git a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp index 41541b5c375..67aa66cb051 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp +++ b/src/coreComponents/physicsSolvers/multiphysics/SinglePhasePoromechanicsEmbeddedFractures.cpp @@ -28,6 +28,7 @@ #include "physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEFEM.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsLagrangianFEM.hpp" #include "physicsSolvers/solidMechanics/SolidMechanicsFields.hpp" +#include "finiteVolume/FluxApproximationBase.hpp" namespace geos diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp index 84e68734d4a..d2a2b413126 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp @@ -20,8 +20,8 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSCONFORMINGFRACTURES_HPP #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSCONFORMINGFRACTURES_HPP -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" #include "codingUtilities/Utilities.hpp" namespace geos @@ -31,7 +31,7 @@ namespace singlePhasePoromechanicsConformingFracturesKernels { template< integer NUM_EQN, integer NUM_DOF > -class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > +class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > { public: @@ -44,7 +44,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; @@ -64,7 +64,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse using AbstractBase::m_dens; using AbstractBase::m_dDens_dPres; - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using Base::numDof; using Base::numEqn; using Base::maxNumElems; @@ -191,21 +191,21 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse localIndex const subRegionIndex[2] = {m_sesri[iconn][k[0]], m_sesri[iconn][k[1]]}; localIndex const elementIndex[2] = {m_sei[iconn][k[0]], m_sei[iconn][k[1]]}; - fluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, - trans, - dTrans, - m_pres, - m_gravCoef, - m_dens, - m_dDens_dPres, - m_mob, - m_dMob_dPres, - alpha, - mobility, - potGrad, - fluxVal, - dFlux_dP, - dFlux_dTrans ); + singlePhaseFluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, + trans, + dTrans, + m_pres, + m_gravCoef, + m_dens, + m_dDens_dPres, + m_mob, + m_dMob_dPres, + alpha, + mobility, + potGrad, + fluxVal, + dFlux_dP, + dFlux_dTrans ); // populate local flux vector and derivatives stack.localFlux[k[0]* numDof] += m_dt * fluxVal; @@ -269,7 +269,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp index 5092012e423..2cb1dec4ecc 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp @@ -20,8 +20,8 @@ #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSEMBEDDEDFRACTURES_HPP #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICSEMBEDDEDFRACTURES_HPP -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/FluxKernelsHelper.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernel.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxKernelsHelper.hpp" #include "codingUtilities/Utilities.hpp" namespace geos @@ -31,7 +31,7 @@ namespace singlePhasePoromechanicsEmbeddedFracturesKernels { template< integer NUM_EQN, integer NUM_DOF > -class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > +class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper > { public: @@ -44,7 +44,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using AbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using AbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = AbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = AbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = AbstractBase::SinglePhaseFluidAccessors; @@ -63,7 +63,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse using AbstractBase::m_dens; using AbstractBase::m_dDens_dPres; - using Base = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using Base = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using Base::numDof; using Base::numEqn; using Base::maxNumElems; @@ -181,21 +181,21 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse real64 mobility = 0.0; real64 potGrad = 0.0; - fluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, - trans, - dTrans, - m_pres, - m_gravCoef, - m_dens, - m_dDens_dPres, - m_mob, - m_dMob_dPres, - alpha, - mobility, - potGrad, - fluxVal, - dFlux_dP, - dFlux_dTrans ); + singlePhaseFluxKernelsHelper::computeSinglePhaseFlux( regionIndex, subRegionIndex, elementIndex, + trans, + dTrans, + m_pres, + m_gravCoef, + m_dens, + m_dDens_dPres, + m_mob, + m_dMob_dPres, + alpha, + mobility, + potGrad, + fluxVal, + dFlux_dP, + dFlux_dTrans ); @@ -239,7 +239,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FaceBasedAsse /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp index 0621ec04d46..c9eb1dcafaf 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp @@ -21,6 +21,7 @@ #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_THERMALSINGLEPHASEPOROMECHANICSCONFORMINGFRACTURES_HPP #include "physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluxComputeKernelBase.hpp" namespace geos { @@ -42,7 +43,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = SinglePhaseFVMAbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFluidAccessors; @@ -56,7 +57,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr using SinglePhaseFVMAbstractBase::m_mob; using SinglePhaseFVMAbstractBase::m_dens; - using SinglePhaseFVMBase = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using SinglePhaseFVMBase = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using SinglePhaseFVMBase::numDof; using SinglePhaseFVMBase::numEqn; using SinglePhaseFVMBase::maxNumElems; @@ -205,25 +206,25 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr real64 trans[2] = {stack.transmissibility[0][0], stack.transmissibility[0][1]}; real64 dMassFlux_dT[2]{}; - fluxKernelsHelper::computeEnthalpyFlux( seri, sesri, sei, - trans, - m_enthalpy, - m_dEnthalpy_dPres, - m_dEnthalpy_dTemp, - m_gravCoef, - m_dDens_dTemp, - m_dMob_dTemp, - alpha, - mobility, - potGrad, - massFlux, - dMassFlux_dTrans, - dMassFlux_dP, - dMassFlux_dT, - stack.energyFlux, - stack.dEnergyFlux_dTrans, - stack.dEnergyFlux_dP, - stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeEnthalpyFlux( seri, sesri, sei, + trans, + m_enthalpy, + m_dEnthalpy_dPres, + m_dEnthalpy_dTemp, + m_gravCoef, + m_dDens_dTemp, + m_dMob_dTemp, + alpha, + mobility, + potGrad, + massFlux, + dMassFlux_dTrans, + dMassFlux_dP, + dMassFlux_dT, + stack.energyFlux, + stack.dEnergyFlux_dTrans, + stack.dEnergyFlux_dP, + stack.dEnergyFlux_dT ); // add dMassFlux_dT to localFluxJacobian for( integer ke = 0; ke < 2; ++ke ) @@ -260,7 +261,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; // Step 2: compute temperature difference at the interface - fluxKernelsHelper::computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); // add energyFlux and its derivatives to localFlux and localFluxJacobian stack.localFlux[k[0]*numEqn + numEqn - 1] += m_dt * stack.energyFlux; @@ -331,7 +332,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsConformingFr /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp index d62a283e364..03690cbf27d 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp @@ -42,7 +42,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac template< typename VIEWTYPE > using ElementViewConst = ElementRegionManager::ElementViewConst< VIEWTYPE >; - using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FaceBasedAssemblyKernelBase; + using SinglePhaseFVMAbstractBase = singlePhaseFVMKernels::FluxComputeKernelBase; using DofNumberAccessor = SinglePhaseFVMAbstractBase::DofNumberAccessor; using SinglePhaseFlowAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFlowAccessors; using SinglePhaseFluidAccessors = SinglePhaseFVMAbstractBase::SinglePhaseFluidAccessors; @@ -56,7 +56,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac using SinglePhaseFVMAbstractBase::m_mob; using SinglePhaseFVMAbstractBase::m_dens; - using SinglePhaseFVMBase = singlePhaseFVMKernels::FaceBasedAssemblyKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; + using SinglePhaseFVMBase = singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, SurfaceElementStencilWrapper >; using SinglePhaseFVMBase::numDof; using SinglePhaseFVMBase::numEqn; using SinglePhaseFVMBase::maxNumElems; @@ -204,25 +204,25 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac real64 trans[2] = {stack.transmissibility[0][0], stack.transmissibility[0][1]}; real64 dMassFlux_dT[2]{}; - fluxKernelsHelper::computeEnthalpyFlux( seri, sesri, sei, - trans, - m_enthalpy, - m_dEnthalpy_dPres, - m_dEnthalpy_dTemp, - m_gravCoef, - m_dDens_dTemp, - m_dMob_dTemp, - alpha, - mobility, - potGrad, - massFlux, - dMassFlux_dTrans, - dMassFlux_dP, - dMassFlux_dT, - stack.energyFlux, - stack.dEnergyFlux_dTrans, - stack.dEnergyFlux_dP, - stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeEnthalpyFlux( seri, sesri, sei, + trans, + m_enthalpy, + m_dEnthalpy_dPres, + m_dEnthalpy_dTemp, + m_gravCoef, + m_dDens_dTemp, + m_dMob_dTemp, + alpha, + mobility, + potGrad, + massFlux, + dMassFlux_dTrans, + dMassFlux_dP, + dMassFlux_dT, + stack.energyFlux, + stack.dEnergyFlux_dTrans, + stack.dEnergyFlux_dP, + stack.dEnergyFlux_dT ); for( localIndex i=0; i < 3; i++ ) { @@ -271,7 +271,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )}; // Step 2: compute temperature difference at the interface - fluxKernelsHelper::computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); + singlePhaseFluxKernelsHelper::computeConductiveFlux( seri, sesri, sei, m_temp, thermalTrans, stack.energyFlux, stack.dEnergyFlux_dT ); // add energyFlux and its derivatives to localFlux and localFluxJacobian stack.localFlux[k[0]*numEqn + numEqn - 1] += m_dt * stack.energyFlux; @@ -343,7 +343,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory { diff --git a/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt b/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt index c21190560cf..800fae6f0db 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt +++ b/src/coreComponents/unitTests/fluidFlowTests/CMakeLists.txt @@ -1,6 +1,6 @@ # Specify list of tests set( gtest_geosx_tests - testSinglePhaseBaseKernels.cpp + testSinglePhaseMobilityKernel.cpp testThermalCompMultiphaseFlow.cpp testThermalSinglePhaseFlow.cpp testFlowStatistics.cpp diff --git a/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp b/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp similarity index 96% rename from src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp rename to src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp index cb4c3c98944..b48cb9d4cf8 100644 --- a/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp +++ b/src/coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp @@ -15,7 +15,7 @@ // Source includes #include "mainInterface/initialization.hpp" -#include "physicsSolvers/fluidFlow/kernels/SinglePhaseBaseKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/singlePhase/MobilityKernel.hpp" // TPL includes #include diff --git a/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst b/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst index 4d8c48baf17..45712596faa 100644 --- a/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst +++ b/src/docs/sphinx/developerGuide/Contributing/UnitTests.rst @@ -11,12 +11,12 @@ GEOS Specific Recommendations An informative example is ``testSinglePhaseBaseKernels`` which tests the single phase flow mobility and accumulation kernels on a variety of inputs. -.. literalinclude:: ../../../../coreComponents/unitTests/fluidFlowTests/testSinglePhaseBaseKernels.cpp +.. literalinclude:: ../../../../coreComponents/unitTests/fluidFlowTests/testSinglePhaseMobilityKernel.cpp :language: c++ :start-after: // Sphinx start after test mobility :end-before: // Sphinx end before test mobility -*[Source: coreComponents/physicsSolvers/fluidFlow/unitTests/testSinglePhaseBaseKernels.cpp]* +*[Source: coreComponents/physicsSolvers/fluidFlow/unitTests/testSinglePhaseMobilityKernel.cpp]* What makes this such a good test is that it depends on very little other than kernels themselves. There is no need to involve the data repository or parse an XML file. Sometimes however this is not possible, or at least not without a significant duplication of code. In this case it is better to embed the XML file into the test source as a string instead of creating a separate XML file and passing it to the test as a command line argument or hard coding the path. One example of this is ``testLaplaceFEM`` which tests the laplacian solver. The embedded XML is shown below.