From 3b0d90740a1c4c4e5ddd2062542988d4aee049ca Mon Sep 17 00:00:00 2001 From: Pavel Tomin Date: Sun, 10 Nov 2024 18:46:26 -0600 Subject: [PATCH] fix: Compositional flow kernels - split into separate files, bugfix for gravity treatment in flux for thermal (#3374) --- .integrated_tests.yaml | 2 +- BASELINE_NOTES.md | 4 + .../fluid/multifluid/MultiFluidSelector.hpp | 2 +- .../physicsSolvers/fluidFlow/CMakeLists.txt | 50 +- .../fluidFlow/CompositionalMultiphaseBase.cpp | 22 +- .../fluidFlow/CompositionalMultiphaseFVM.cpp | 47 +- .../CompositionalMultiphaseHybridFVM.cpp | 7 +- .../CompositionalMultiphaseStatistics.cpp | 8 +- .../ReactiveCompositionalMultiphaseOBL.cpp | 2 +- .../compositional/AccumulationKernel.hpp | 510 ++++ .../kernels/compositional/AquiferBCKernel.cpp | 268 ++ .../kernels/compositional/AquiferBCKernel.hpp | 131 + .../kernels/compositional/C1PPUPhaseFlux.hpp | 228 ++ ...MultiphaseFVMKernels.cpp => CFLKernel.cpp} | 270 +- .../kernels/compositional/CFLKernel.hpp | 184 ++ .../CapillaryPressureUpdateKernel.hpp | 73 + ...ompositionalMultiphaseHybridFVMKernels.hpp | 5 +- .../DiffusionDispersionFluxComputeKernel.hpp | 775 +++++ .../DirichletFluxComputeKernel.hpp | 558 ++++ ...s.hpp => DissipationFluxComputeKernel.hpp} | 73 +- .../compositional/FluidUpdateKernel.hpp | 77 + .../compositional/FluxComputeKernel.hpp | 575 ++++ .../compositional/FluxComputeKernelBase.cpp | 65 + .../compositional/FluxComputeKernelBase.hpp | 181 ++ .../GlobalComponentFractionKernel.hpp | 144 + .../HydrostaticPressureKernel.hpp | 356 +++ ...VMKernelUtilities.hpp => IHUPhaseFlux.hpp} | 569 +--- ...rmalCompositionalMultiphaseBaseKernels.hpp | 2508 ----------------- ...ermalCompositionalMultiphaseFVMKernels.hpp | 2388 ---------------- .../compositional/KernelLaunchSelectors.hpp | 159 ++ .../kernels/compositional/PPUPhaseFlux.hpp | 162 ++ .../compositional/PhaseComponentFlux.hpp | 128 + .../compositional/PhaseMobilityKernel.hpp | 241 ++ .../PhaseVolumeFractionKernel.hpp | 256 ++ .../kernels/compositional/PotGrad.hpp | 208 ++ .../compositional/PropertyKernelBase.hpp | 91 + ...ctiveCompositionalMultiphaseOBLKernels.hpp | 68 +- .../RelativePermeabilityUpdateKernel.hpp | 73 + .../compositional/ResidualNormKernel.hpp | 191 ++ .../SolidInternalEnergyUpdateKernel.hpp | 55 + .../compositional/SolutionCheckKernel.hpp | 334 +++ .../SolutionScalingAndCheckingKernelBase.hpp | 182 ++ .../compositional/SolutionScalingKernel.hpp | 383 +++ ...ls.hpp => StabilizedFluxComputeKernel.hpp} | 64 +- .../compositional/StatisticsKernel.hpp | 194 ++ .../ThermalAccumulationKernel.hpp | 345 +++ ...rmalCompositionalMultiphaseBaseKernels.hpp | 1062 ------- ...ermalCompositionalMultiphaseFVMKernels.hpp | 1444 ---------- ...alDiffusionDispersionFluxComputeKernel.hpp | 352 +++ .../ThermalDirichletFluxComputeKernel.hpp | 484 ++++ .../ThermalFluxComputeKernel.hpp | 572 ++++ .../ThermalPhaseMobilityKernel.hpp | 154 + .../ThermalPhaseVolumeFractionKernel.hpp | 140 + .../ThermalResidualNormKernel.hpp | 241 ++ .../ThermalSolutionCheckKernel.hpp | 181 ++ .../ThermalSolutionScalingKernel.hpp | 226 ++ .../wells/CompositionalMultiphaseWell.cpp | 17 +- .../CompositionalMultiphaseWellKernels.hpp | 37 +- ...rmalCompositionalMultiphaseWellKernels.hpp | 12 +- .../CoupledReservoirAndWellKernels.hpp | 14 +- ...ePhasePoromechanicsConformingFractures.hpp | 2 +- ...glePhasePoromechanicsEmbeddedFractures.hpp | 2 +- ...ePhasePoromechanicsConformingFractures.hpp | 2 +- ...glePhasePoromechanicsEmbeddedFractures.hpp | 2 +- 64 files changed, 9742 insertions(+), 8418 deletions(-) create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AccumulationKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.cpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/AquiferBCKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/C1PPUPhaseFlux.hpp rename src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/{IsothermalCompositionalMultiphaseFVMKernels.cpp => CFLKernel.cpp} (58%) create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CapillaryPressureUpdateKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DiffusionDispersionFluxComputeKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DirichletFluxComputeKernel.hpp rename src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/{DissipationCompositionalMultiphaseFVMKernels.hpp => DissipationFluxComputeKernel.hpp} (86%) create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.cpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/FluxComputeKernelBase.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/GlobalComponentFractionKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/HydrostaticPressureKernel.hpp rename src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/{IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp => IHUPhaseFlux.hpp} (82%) delete mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp delete mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PPUPhaseFlux.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseComponentFlux.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseMobilityKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PotGrad.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/PropertyKernelBase.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/RelativePermeabilityUpdateKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ResidualNormKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolidInternalEnergyUpdateKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionCheckKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingAndCheckingKernelBase.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/SolutionScalingKernel.hpp rename src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/{StabilizedCompositionalMultiphaseFVMKernels.hpp => StabilizedFluxComputeKernel.hpp} (86%) create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalAccumulationKernel.hpp delete mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseBaseKernels.hpp delete mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseFVMKernels.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDiffusionDispersionFluxComputeKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalDirichletFluxComputeKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalFluxComputeKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseMobilityKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalResidualNormKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionCheckKernel.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalSolutionScalingKernel.hpp diff --git a/.integrated_tests.yaml b/.integrated_tests.yaml index 733e3a80147..71364ebb802 100644 --- a/.integrated_tests.yaml +++ b/.integrated_tests.yaml @@ -1,6 +1,6 @@ baselines: bucket: geosx - baseline: integratedTests/baseline_integratedTests-pr3372-8610-4b9a7b3 + baseline: integratedTests/baseline_integratedTests-pr3374-8621-bbb3cb2 allow_fail: all: '' diff --git a/BASELINE_NOTES.md b/BASELINE_NOTES.md index d9bc0a2e825..3af18f0dec8 100644 --- a/BASELINE_NOTES.md +++ b/BASELINE_NOTES.md @@ -6,6 +6,10 @@ This file is designed to track changes to the integrated test baselines. Any developer who updates the baseline ID in the .integrated_tests.yaml file is expected to create an entry in this file with the pull request number, date, and their justification for rebaselining. These notes should be in reverse-chronological order, and use the following time format: (YYYY-MM-DD). +PR #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. 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/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt index 46712916a82..651d9135e08 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt +++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt @@ -45,14 +45,48 @@ set( physicsSolvers_headers fluidFlow/kernels/singlePhase/ThermalFluxComputeKernel.hpp fluidFlow/kernels/singlePhase/proppant/ProppantBaseKernels.hpp fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.hpp - fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp - fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseBaseKernels.hpp - fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.hpp - fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp - fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseFVMKernels.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/StabilizedCompositionalMultiphaseFVMKernels.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/SinglePhaseWell.hpp @@ -86,7 +120,9 @@ set( physicsSolvers_sources fluidFlow/SourceFluxStatistics.cpp fluidFlow/StencilDataCollection.cpp fluidFlow/kernels/singlePhase/proppant/ProppantFluxKernels.cpp - fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.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 diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseBase.cpp index 62097a5b9ea..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/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.hpp" // TODO this should not be here -#include "physicsSolvers/fluidFlow/kernels/compositional/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 7c640319397..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/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/StabilizedCompositionalMultiphaseFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/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 1901b5570c4..bedfa0c3261 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.cpp @@ -31,7 +31,10 @@ #include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseBaseKernels.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 a065a32ca64..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/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.hpp" +#include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" #include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" diff --git a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp index ff324042411..3d8143e0d83 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/ReactiveCompositionalMultiphaseOBL.cpp @@ -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/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/compositional/IsothermalCompositionalMultiphaseFVMKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp similarity index 58% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.cpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CFLKernel.cpp index ebceae552f0..b416573af0b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/CompositionalMultiphaseHybridFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/CompositionalMultiphaseHybridFVMKernels.hpp index 14b19626972..c388cad6da5 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/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/compositional/DissipationCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp similarity index 86% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationCompositionalMultiphaseFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/DissipationFluxComputeKernel.hpp index 7a316a92355..1b4183c8c1a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp similarity index 82% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernelUtilities.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IHUPhaseFlux.hpp index 323f3e362d0..ec9b3c55783 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/IsothermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp deleted file mode 100644 index a80f991003f..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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 ); - } ); - } - -}; - -/******************************** SolutionScalingKernelKernel ********************************/ - -/** - * @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/compositional/IsothermalCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/IsothermalCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index 3cad40cf9fe..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/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/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/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ReactiveCompositionalMultiphaseOBLKernels.hpp index 168bb83da93..bc76898511d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/StabilizedCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp similarity index 86% rename from src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedCompositionalMultiphaseFVMKernels.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/StabilizedFluxComputeKernel.hpp index 62bab9f3a23..de9e92c8b80 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/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/ThermalCompositionalMultiphaseBaseKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseBaseKernels.hpp deleted file mode 100644 index 4b07977241c..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/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/compositional/ThermalCompositionalMultiphaseFVMKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseFVMKernels.hpp deleted file mode 100644 index bec2c3217c4..00000000000 --- a/src/coreComponents/physicsSolvers/fluidFlow/kernels/compositional/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/compositional/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/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/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 40257ddf2fd..95f59c179ec 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -42,9 +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/compositional/IsothermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/kernels/compositional/ThermalCompositionalMultiphaseBaseKernels.hpp" -#include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.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" @@ -1386,7 +1393,7 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain, auto const subRegionData = m_isThermal ? thermalCompositionalMultiphaseBaseKernels:: - ScalingForSystemSolutionKernelFactory:: + SolutionScalingKernelFactory:: createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange, m_maxAbsolutePresChange, m_maxRelativeTempChange, @@ -1405,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/kernels/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp index c82ea94e590..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/compositional/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/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp index 5befe3e9aa7..d2a2b413126 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsConformingFractures.hpp @@ -269,7 +269,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FluxComputeKe /** - * @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 654ee0b3594..2cb1dec4ecc 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/SinglePhasePoromechanicsEmbeddedFractures.hpp @@ -239,7 +239,7 @@ class ConnectorBasedAssemblyKernel : public singlePhaseFVMKernels::FluxComputeKe /** - * @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 e82a918fa09..c9eb1dcafaf 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsConformingFractures.hpp @@ -332,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 1b39b1b44cb..03690cbf27d 100644 --- a/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp +++ b/src/coreComponents/physicsSolvers/multiphysics/poromechanicsKernels/ThermalSinglePhasePoromechanicsEmbeddedFractures.hpp @@ -343,7 +343,7 @@ class ConnectorBasedAssemblyKernel : public singlePhasePoromechanicsEmbeddedFrac /** - * @class FaceBasedAssemblyKernelFactory + * @class ConnectorBasedAssemblyKernelFactory */ class ConnectorBasedAssemblyKernelFactory {