diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml
index 88decc83bda..429f5836282 100644
--- a/.github/workflows/ci_tests.yml
+++ b/.github/workflows/ci_tests.yml
@@ -204,14 +204,15 @@ jobs:
GEOS_ENABLE_BOUNDS_CHECK: OFF
HOST_CONFIG: /spack-generated.cmake
- - name: Ubuntu (22.04, clang 15.0.7, open-mpi 4.1.2)
- CMAKE_BUILD_TYPE: Release
- DOCKER_REPOSITORY: geosx/ubuntu22.04-clang15
- ENABLE_HYPRE: ON
- ENABLE_TRILINOS: OFF
- GEOS_ENABLE_BOUNDS_CHECK: ON
- BUILD_SHARED_LIBS: ON
- HOST_CONFIG: /spack-generated.cmake
+ #- name: Ubuntu (22.04, clang 15.0.7, open-mpi 4.1.2)
+ # CMAKE_BUILD_TYPE: Release
+ # DOCKER_REPOSITORY: geosx/ubuntu22.04-clang15
+ # ENABLE_HYPRE: ON
+ ## ENABLE_TRILINOS: OFF
+ # GEOS_ENABLE_BOUNDS_CHECK: ON
+ # BUILD_SHARED_LIBS: ON
+ # HOST_CONFIG: /spack-generated.cmake
+ # USE_SCCACHE: false
#- name: Sherlock CPU (centos 7.9.2009, gcc 10.1.0, open-mpi 4.1.2, openblas 0.3.10)
# CMAKE_BUILD_TYPE: Release
diff --git a/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml b/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml
index 89b9cc7dc86..1218d8156a2 100644
--- a/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml
+++ b/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_benchmark.xml
@@ -1,294 +1,390 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_smoke.xml b/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_smoke.xml
index 19a577bde98..3e4fe211b1b 100644
--- a/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_smoke.xml
+++ b/inputFiles/compositionalMultiphaseFlow/soreideWhitson/1D_100cells/1D_smoke.xml
@@ -1,294 +1,384 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml
index f2c31503e8a..4d4ff61234c 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_direct_base.xml
@@ -1,8 +1,6 @@
-
-
+ useSurfaceConditions="1"
+ surfacePressure="101325"
+ surfaceTemperature="288.71"
+ control="totalVolRate">
+
+
+
-
+
-
+
+ name="fluidTPFA"/>
@@ -80,13 +83,16 @@
solidModelName="nullSolid"
porosityModelName="rockPorosity"
permeabilityModelName="rockPerm"/>
+
+
+
@@ -94,9 +100,8 @@
-
+ wettingNonWettingRelPermTableNames="{ waterRelativePermeabilityTable, gasRelativePermeabilityTable }"/>
+
-
-
-
+
+
+
+
-
@@ -152,11 +157,13 @@
name="initCO2CompFracTable"
coordinates="{ -3238.2, -2506.13 }"
values="{ 0.000001, 0.000001 }"/>
+
-
@@ -165,37 +172,36 @@
name="waterRelativePermeabilityTable"
coordinateFiles="{ tables/phaseVolumeFraction_water.txt }"
voxelFile="tables/relPerm_water.txt"/>
+
+ voxelFile="tables/relPerm_gas.txt"/>
-
+ voxelFile="tables/capPres_water.txt"/>
-
+ interpolation="linear"/>
-
+ interpolation="linear"/>
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml
index 8e76b08905b..e585c6e4238 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_drainageOnly_iterative_base.xml
@@ -1,10 +1,7 @@
-
-
-
-
-
-
-
+ control="totalVolRate">
+
+
+
+ control="massRate">
+
+
+
+ control="massRate">
+
+
+
-
-
-
-
+
+ name="fluidTPFA"/>
-
-
-
+
+
+
-
-
-
+ wettingNonWettingRelPermTableNames="{ waterRelativePermeabilityTable, gasRelativePermeabilityTable }"/>
-
-
-
-
-
-
-
-
+
+
+
-
@@ -204,11 +199,13 @@
name="initCO2CompFracTable"
coordinates="{ -3238.2, -2506.13 }"
values="{ 0.000001, 0.000001 }"/>
+
-
@@ -217,43 +214,43 @@
name="waterRelativePermeabilityTable"
coordinateFiles="{ tables/phaseVolumeFraction_water.txt }"
voxelFile="tables/relPerm_water.txt"/>
+
+ voxelFile="tables/relPerm_gas.txt"/>
-
+ voxelFile="tables/capPres_water.txt"/>
-
+ interpolation="linear"/>
-
+ interpolation="linear"/>
-
diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml
index c731abcf696..83ca125931e 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_direct_base.xml
@@ -1,8 +1,6 @@
-
-
+ useSurfaceConditions="1"
+ surfacePressure="101325"
+ surfaceTemperature="288.71"
+ control="totalVolRate">
+
+
+
-
+
-
+
+ name="fluidTPFA"/>
@@ -80,26 +83,27 @@
solidModelName="nullSolid"
porosityModelName="rockPorosity"
permeabilityModelName="rockPerm"/>
+
+
+
-
-
+
-
-
-
-
-
+
+
+
+
-
@@ -157,59 +159,61 @@
name="initCO2CompFracTable"
coordinates="{ -3238.2, -2506.13 }"
values="{ 0.000001, 0.000001 }"/>
+
+
-
+ voxelFile="tables/capPres_water.txt"/>
-
+ interpolation="linear"/>
-
+ interpolation="linear"/>
-
-
+
+
+
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_iterative_base.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_iterative_base.xml
index ee1af0ef88d..6067d36b757 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_iterative_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Class09Pb3/class09_pb3_hystRelperm_iterative_base.xml
@@ -1,8 +1,6 @@
-
-
+ control="totalVolRate">
+
+
+
-
+
-
+
+ name="fluidTPFA"/>
@@ -84,28 +87,27 @@
solidModelName="nullSolid"
porosityModelName="rockPorosity"
permeabilityModelName="rockPerm"/>
+
+
+
-
-
-
-
+
-
-
+
+
+
+
-
@@ -161,10 +163,12 @@
name="initCO2CompFracTable"
coordinates="{ -3238.2, -2506.13 }"
values="{ 0.000001, 0.000001 }"/>
+
+
+
+ voxelFile="tables/relPerm_gas.txt"/>
+ voxelFile="tables/capPres_water.txt"/>
-
+ interpolation="linear"/>
-
+ interpolation="linear"/>
-
+
+
+
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml
index 048e88999d7..742d818218b 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_direct.xml
@@ -1,7 +1,6 @@
-
+ control="BHP">
+
+
+
-
-
-
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
-
-
-
-
-
-
-
-
@@ -279,7 +327,6 @@
materialList="{ fluid }"/>
-
-
-
-
-
@@ -373,11 +416,8 @@
-
-
-
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml
index 615688bef78..fa47c6541e9 100644
--- a/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml
+++ b/inputFiles/compositionalMultiphaseWell/benchmarks/Egg/deadOilEgg_base_iterative.xml
@@ -1,7 +1,6 @@
-
+ control="BHP">
+
+
+
-
-
-
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
-
-
-
-
-
-
-
-
@@ -281,7 +329,6 @@
materialList="{ fluid }"/>
-
-
-
-
-
@@ -375,11 +418,8 @@
-
-
-
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml b/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml
index 7ebac080cbc..14479ff4132 100644
--- a/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d.xml
@@ -2,7 +2,6 @@
-
-
+
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
-
-
-
-
+
-
+
-
+
-
@@ -148,12 +153,14 @@
name="region"
cellBlocks="{ * }"
materialList="{ fluid, rock, relperm, cappres }"/>
+
+
+ materialList="{ fluid }"/>
@@ -163,7 +170,7 @@
surfaceDensities="{ 800.907131537, 0.856234902739, 1020.3440 }"
componentMolarWeight="{ 120e-3, 25e-3, 18e-3 }"
tableFiles="{ pvto_bo.txt, pvtg_norv_bo.txt, pvtw_bo.txt }"/>
-
+
-
+
-
-
+
+
+ scale="0.2"/>
+
-
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 10000, 9025, 8100, 7225, 6400, 5625, 4900, 4225, 3600, 3025, 2500, 2025, 1600, 1225, 900, 625, 400, 225, 100, 25, 0 }"/>
+
-
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 50, 200, 450, 800, 1250, 1800, 2450, 3200, 4050, 5000, 6050, 7200, 8450, 9800, 11250, 12800, 14450, 16200, 18050, 20000 }"/>
-
+
-
+
-
+
-
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d_stone2.xml b/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d_stone2.xml
index ce669961545..5df4a8cf991 100644
--- a/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d_stone2.xml
+++ b/inputFiles/compositionalMultiphaseWell/black_oil_wells_saturated_3d_stone2.xml
@@ -2,7 +2,6 @@
-
-
+
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
-
+
-
+
-
@@ -147,12 +153,14 @@
name="region"
cellBlocks="{ * }"
materialList="{ fluid, rock, relperm, cappres }"/>
+
+
+ materialList="{ fluid }"/>
@@ -162,7 +170,7 @@
surfaceDensities="{ 800.907131537, 0.856234902739, 1020.3440 }"
componentMolarWeight="{ 120e-3, 25e-3, 18e-3 }"
tableFiles="{ pvto_bo.txt, pvtg_norv_bo.txt, pvtw_bo.txt }"/>
-
+
-
+
-
-
+
+
+ scale="0.2"/>
+
-
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 0.0025, 0.0100, 0.0225, 0.0400, 0.0625, 0.0900, 0.1225, 0.1600, 0.2025, 0.2500, 0.3025, 0.3600, 0.4225, 0.4900, 0.5625, 0.6400, 0.7225, 0.8100, 0.9025, 1.0000 }"/>
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 10000, 9025, 8100, 7225, 6400, 5625, 4900, 4225, 3600, 3025, 2500, 2025, 1600, 1225, 900, 625, 400, 225, 100, 25, 0 }"/>
+
-
+ coordinates="{ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00 }"
+ values="{ 0, 50, 200, 450, 800, 1250, 1800, 2450, 3200, 4050, 5000, 6050, 7200, 8450, 9800, 11250, 12800, 14450, 16200, 18050, 20000 }"/>
-
+
-
+
-
+
-
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml b/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml
index 323b9a144c6..b2e5a4c7d91 100644
--- a/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d.xml
@@ -2,7 +2,6 @@
-
-
+
+
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
-
-
-
-
-
+
-
-
+
-
+
-
@@ -148,12 +154,14 @@
name="region"
cellBlocks="{ * }"
materialList="{ fluid, rock, relperm }"/>
+
+
+ materialList="{ fluid }"/>
@@ -163,7 +171,7 @@
surfaceDensities="{ 800.907131537, 0.856234902739, 1020.3440 }"
componentMolarWeight="{ 120e-3, 25e-3, 18e-3 }"
tableFiles="{ pvto_bo.txt, pvtg_norv_bo.txt, pvtw_bo.txt }"/>
-
+
-
-
+
+
+ scale="0.1"/>
+
-
+
-
+
-
+ name="vtkOutput"/>
+
-
-
diff --git a/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d_stone2.xml b/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d_stone2.xml
index ea41c8adf9c..464449a53f4 100644
--- a/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d_stone2.xml
+++ b/inputFiles/compositionalMultiphaseWell/black_oil_wells_unsaturated_3d_stone2.xml
@@ -1,260 +1,267 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml b/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml
index bea2c48815d..2ba87aa5909 100644
--- a/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml
+++ b/inputFiles/compositionalMultiphaseWell/compositional_multiphase_wells_1d.xml
@@ -30,20 +30,30 @@
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -58,7 +68,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
+ name="fluidTPFA"/>
@@ -175,7 +182,6 @@
-
-
-
+ control="BHP">
+
+
+
+ control="phaseVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
-
-
@@ -69,7 +81,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
+ name="fluidTPFA"/>
@@ -223,7 +231,6 @@
-
-
+ control="BHP">
+
+
+
+ control="phaseVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -78,7 +93,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
+ name="fluidTPFA"/>
@@ -223,7 +234,6 @@
-
-
-
-
+
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -77,7 +92,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseWell/dome_soreide_whitson_base.xml b/inputFiles/compositionalMultiphaseWell/dome_soreide_whitson_base.xml
index 2e00878f00e..e5f85ebfbdd 100644
--- a/inputFiles/compositionalMultiphaseWell/dome_soreide_whitson_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/dome_soreide_whitson_base.xml
@@ -1,287 +1,339 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inputFiles/compositionalMultiphaseWell/isothm_mass_inj_table.xml b/inputFiles/compositionalMultiphaseWell/isothm_mass_inj_table.xml
index 14076fab917..cf1631e6f94 100644
--- a/inputFiles/compositionalMultiphaseWell/isothm_mass_inj_table.xml
+++ b/inputFiles/compositionalMultiphaseWell/isothm_mass_inj_table.xml
@@ -10,7 +10,7 @@
initialDt="1e2"
targetRegions="{ region, injwell }">
-
+ targetRegions="{ region }"/>
-
+ control="massRate">
+
+
+
+
@@ -83,10 +85,8 @@
-
-
@@ -94,8 +94,6 @@
name="sink"
xMin="{ 89.99, 89.99, -0.01 }"
xMax="{ 101.01, 101.01, 1.01 }"/>
-
-
-
-
@@ -143,25 +142,28 @@
name="region"
cellBlocks="{ cb }"
materialList="{ fluid, rock, relperm }"/>
+
-
+
+
+
@@ -181,11 +183,9 @@
phaseMinVolumeFraction="{ 0.0, 0.0 }"
phaseRelPermExponent="{ 1.5, 1.5 }"
phaseRelPermMaxValue="{ 0.9, 0.9 }"/>
-
-
+
+
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/isothm_vol_inj_table.xml b/inputFiles/compositionalMultiphaseWell/isothm_vol_inj_table.xml
index d39421e36fc..7c198945edd 100644
--- a/inputFiles/compositionalMultiphaseWell/isothm_vol_inj_table.xml
+++ b/inputFiles/compositionalMultiphaseWell/isothm_vol_inj_table.xml
@@ -10,7 +10,7 @@
initialDt="1e2"
targetRegions="{ region, injwell }">
-
+ targetRegions="{ region }"/>
-
+ control="totalVolRate">
+
+
+
+
@@ -82,10 +85,8 @@
-
-
@@ -93,8 +94,6 @@
name="sink"
xMin="{ 89.99, 89.99, -0.01 }"
xMax="{ 101.01, 101.01, 1.01 }"/>
-
-
-
-
-
@@ -148,25 +149,28 @@
name="region"
cellBlocks="{ cb }"
materialList="{ fluid, rock, relperm }"/>
+
-
+
+
+
@@ -186,11 +190,9 @@
phaseMinVolumeFraction="{ 0.0, 0.0 }"
phaseRelPermExponent="{ 1.5, 1.5 }"
phaseRelPermMaxValue="{ 0.9, 0.9 }"/>
-
-
+
+
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/simpleCo2InjTutorial_base.xml b/inputFiles/compositionalMultiphaseWell/simpleCo2InjTutorial_base.xml
index 705b4934fb9..5d4f887ad1e 100644
--- a/inputFiles/compositionalMultiphaseWell/simpleCo2InjTutorial_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/simpleCo2InjTutorial_base.xml
@@ -1,8 +1,6 @@
-
-
+ useSurfaceConditions="1"
+ surfacePressure="101325"
+ surfaceTemperature="288.71"
+ control="totalVolRate">
+
+
+
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
@@ -185,42 +177,37 @@
-
+ sources="{ /Tasks/wellPressureCollection }"
+ filename="wellPressureHistory"/>
-
-
-
+ fieldName="pressure"/>
-
+
-
-
-
-
-
+
+
+
+
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/staged_perf_base.xml b/inputFiles/compositionalMultiphaseWell/staged_perf_base.xml
index 302d728e9b4..9e87e03c62f 100644
--- a/inputFiles/compositionalMultiphaseWell/staged_perf_base.xml
+++ b/inputFiles/compositionalMultiphaseWell/staged_perf_base.xml
@@ -10,11 +10,11 @@
targetRegions="{ reservoir, wellRegion1 }">
+ directParallel="0"/>
+ control="BHP">
+
+
+
-
-
+
+ name="fluidTPFA"/>
@@ -91,7 +93,6 @@
-
@@ -158,34 +159,31 @@
scale="1.0"/>
-
+ name="equil"
+ objectPath="ElementRegions"
+ datumElevation="0"
+ datumPressure="2.214e7"
+ initialPhaseName="water"
+ componentNames="{ co2, water }"
+ componentFractionVsElevationTableNames="{ initCO2CompFracTable, initWaterCompFracTable }"
+ temperatureVsElevationTableName="initTempTable"/>
+ name="initCO2CompFracTable"
+ coordinates="{ -3000.0, 0.0 }"
+ values="{ 0.0, 0.0 }"/>
+ name="initWaterCompFracTable"
+ coordinates="{ -3000.0, 0.0 }"
+ values="{ 1.0, 1.0 }"/>
-
+ name="initTempTable"
+ coordinates="{ -3000.0, 0.0 }"
+ values="{ 368, 288 }"/>
diff --git a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml
index 388b15ca605..ad4a7cc4368 100644
--- a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_3d.xml
@@ -33,28 +33,36 @@
useMass="1">
+ control="phaseVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
-
-
-
+ cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }">
-
+ wettingNonWettingRelPermTableNames="{ waterRelativePermeabilityTable, gasRelativePermeabilityTable }"/>
-
@@ -222,35 +223,37 @@
scale="0.96"/>
-
+
+ voxelFile="relPerm_gas.txt"/>
+
+ voxelFile="capPres_water.txt"/>
+
+
-
diff --git a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_hybrid_3d.xml b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_hybrid_3d.xml
index b7e30e91dcb..f5d6b2a7340 100644
--- a/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_hybrid_3d.xml
+++ b/inputFiles/compositionalMultiphaseWell/staircase_co2_wells_hybrid_3d.xml
@@ -38,25 +38,34 @@
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
-
-
-
-
+
diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml
index 0ca07929f8e..5e1a987f1cc 100644
--- a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml
+++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_fim.xml
@@ -1,13 +1,12 @@
-
-
-
+
+
-
-
+
+ targetRegions="{ channel, barrier }"/>
@@ -55,34 +54,42 @@
useMass="1">
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
-
-
+
+
-
+
+
-
+
-
-
-
diff --git a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml
index e978595a49f..6a336f2fda3 100755
--- a/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml
+++ b/inputFiles/poromechanics/PoroElastic_staircase_co2_3d_sequential.xml
@@ -1,13 +1,12 @@
-
-
-
+
+
-
-
+
+ targetRegions="{ channel, barrier }"/>
@@ -62,34 +61,42 @@
useMass="1">
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
-
-
+
+
-
+
+
-
+
-
-
diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml
index 95f2090ada1..29c208416b7 100644
--- a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml
+++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_fim.xml
@@ -1,13 +1,12 @@
-
-
-
+
+
-
-
+
+ targetRegions="{ channel, barrier }"/>
+ control="BHP">
+
+
+
+ surfacePressure="101325"
+ control="totalVolRate">
+
+
+
-
-
+ minTime="-1e11"
+ maxTime="1e7">
-
+
+
-
+
+
-
-
+
+
-
diff --git a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml
index 0c952c6934f..5f5b8cbc6ba 100755
--- a/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml
+++ b/inputFiles/poromechanics/PoroElastic_staircase_singlephase_3d_sequential.xml
@@ -1,13 +1,12 @@
-
-
-
+
+
-
-
+
+ targetRegions="{ channel, barrier }"/>
+ control="BHP">
+
+
+
+ surfacePressure="101325"
+ control="totalVolRate">
+
+
+
-
-
+ minTime="-1e11"
+ maxTime="1e7">
-
+
+
-
+
-
@@ -118,24 +125,25 @@
name="linearElasticityStatistics"
solidSolverName="linearElasticity"
logLevel="1"/>
+
-
-
+
+
-
diff --git a/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_fim_smoke.xml b/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_fim_smoke.xml
index 0ce10628d75..3660699ecaf 100644
--- a/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_fim_smoke.xml
+++ b/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_fim_smoke.xml
@@ -1,14 +1,16 @@
+
+
-
+
-
+ maxAllowedResidualNorm="1e+15"/>
+ directParallel="0"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
+ logLevel="3"/>
-
+ targetRegions="{ Region, Fault }"
+ temperature="368.15"/>
+ logLevel="2">
+
+
+
@@ -88,47 +95,44 @@
numElementsPerSegment="1">
+ distanceFromHead="250"/>
-
+
+
-
-
-
+ target="/Outputs/vtkOutput"/>
+ target="/Solvers/reservoirSolver"/>
+ target="/Outputs/vtkOutput"/>
+ target="/Outputs/restartOutput"/>
diff --git a/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_seq_smoke.xml b/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_seq_smoke.xml
index d0959438756..5557c612313 100644
--- a/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_seq_smoke.xml
+++ b/inputFiles/poromechanicsFractures/multiphasePoromechanics_FaultModel_well_seq_smoke.xml
@@ -1,14 +1,16 @@
+
+
-
+
-
+ maxAllowedResidualNorm="1e+15"/>
+ directParallel="0"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
+ newtonMaxIter="20"/>
+ preconditionerType="mgr"/>
-
+ targetRegions="{ Region, Fault }"
+ temperature="368.15"/>
+ logLevel="2">
+
+
+
@@ -97,47 +104,44 @@
numElementsPerSegment="1">
+ distanceFromHead="250"/>
-
+
+
-
-
-
+ target="/Outputs/vtkOutput"/>
+ target="/Solvers/reservoirSolver"/>
+ target="/Outputs/vtkOutput"/>
+ target="/Outputs/restartOutput"/>
diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_fim_new_smoke.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_fim_new_smoke.xml
index 07a6e1521ff..369356badf7 100644
--- a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_fim_new_smoke.xml
+++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_fim_new_smoke.xml
@@ -1,14 +1,16 @@
+
+
-
+
-
+ solverType="direct"/>
-
+ logLevel="1"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
-
+ targetRegions="{ Region, Fault }"/>
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
-
+
+
-
-
-
+
-
+
-
+ solverType="direct"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
-
+ targetRegions="{ Region, Fault }"/>
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
-
+
+
-
-
-
+
@@ -5,10 +7,9 @@
-
-
+ logLevel="1"/>
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
-
+ targetRegions="{ Region, Fault }"/>
+ targetRegions="{ wellRegion1, wellRegion2 }"
+ writeCSV="1">
+ logLevel="2"
+ type="producer">
+
+
+
+ logLevel="2"
+ type="injector">
+
+
+
-
+
+
-
-
-
+
@@ -5,10 +7,9 @@
-
+ targetRegions="{ Region, Fault }"
+ discretization="FE1"/>
-
+ targetRegions="{ Region, Fault }"/>
+ targetRegions="{ wellRegion1, wellRegion2 }"
+ writeCSV="1">
+ logLevel="2"
+ type="producer">
+
+
+
+ logLevel="2"
+ type="injector">
+
+
+
-
+
+
-
-
-
+ targetRegions="{ region , wellRegion2 }">
-
+ targetRegions="{ region }"/>
+ control="BHP">
+
+
+
@@ -78,13 +82,13 @@
name="region"
cellBlocks="{ * }"
materialList="{ fluid, rock, thermalCond }"/>
+
-
-
-
-
diff --git a/inputFiles/singlePhaseWell/compressible_single_phase_wells_1d.xml b/inputFiles/singlePhaseWell/compressible_single_phase_wells_1d.xml
index 4b5f64d0287..bd55d92c512 100644
--- a/inputFiles/singlePhaseWell/compressible_single_phase_wells_1d.xml
+++ b/inputFiles/singlePhaseWell/compressible_single_phase_wells_1d.xml
@@ -27,17 +27,27 @@
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -52,7 +62,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -52,7 +62,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
+ distanceFromHead="1.45"
+ skinFactor="1"/>
-
+ targetRegions="{ wellRegion1, wellRegion2 }">
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -53,7 +63,6 @@
ny="{ 1 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
+ targetRegions="{ wellRegion1, wellRegion2, wellRegion3 }">
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ initialPressureCoefficient="0.01"
+ control="totalVolRate">
+
+
+
@@ -60,7 +75,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
+ name="singlePhaseTPFA"/>
diff --git a/inputFiles/singlePhaseWell/incompressible_single_phase_wells_hybrid_2d.xml b/inputFiles/singlePhaseWell/incompressible_single_phase_wells_hybrid_2d.xml
index 743a1f7be70..911c36553c7 100644
--- a/inputFiles/singlePhaseWell/incompressible_single_phase_wells_hybrid_2d.xml
+++ b/inputFiles/singlePhaseWell/incompressible_single_phase_wells_hybrid_2d.xml
@@ -28,24 +28,39 @@
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -60,7 +75,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
+ targetRegions="{ wellRegion1, wellRegion2, wellRegion3 }">
+ control="BHP">
+
+
+
+ control="BHP">
+
+
+
+ initialPressureCoefficient="0.01"
+ control="totalVolRate">
+
+
+
@@ -62,7 +76,6 @@
ny="{ 20 }"
nz="{ 1 }"
cellBlockNames="{ cb1 }">
-
-
-
+ name="singlePhaseTPFA"/>
diff --git a/inputFiles/singlePhaseWell/staircase_single_phase_wells_3d.xml b/inputFiles/singlePhaseWell/staircase_single_phase_wells_3d.xml
index 6789ab90542..c8cb5ca9a9f 100644
--- a/inputFiles/singlePhaseWell/staircase_single_phase_wells_3d.xml
+++ b/inputFiles/singlePhaseWell/staircase_single_phase_wells_3d.xml
@@ -16,7 +16,7 @@
@@ -27,17 +27,27 @@
+ control="totalVolRate">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -51,11 +61,7 @@
nx="{ 5, 5 }"
ny="{ 5, 5 }"
nz="{ 3, 3, 3, 3 }"
- cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0,
- cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1,
- cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2,
- cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }">
-
+ cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }">
-
@@ -172,9 +177,9 @@
diff --git a/inputFiles/singlePhaseWell/staircase_single_phase_wells_hybrid_3d.xml b/inputFiles/singlePhaseWell/staircase_single_phase_wells_hybrid_3d.xml
index 2298a32e483..c9c874c8a07 100644
--- a/inputFiles/singlePhaseWell/staircase_single_phase_wells_hybrid_3d.xml
+++ b/inputFiles/singlePhaseWell/staircase_single_phase_wells_hybrid_3d.xml
@@ -28,19 +28,29 @@
+ control="BHP">
+
+
+
+ control="totalVolRate">
+
+
+
@@ -54,11 +64,7 @@
nx="{ 5, 5 }"
ny="{ 5, 5 }"
nz="{ 3, 3, 3, 3 }"
- cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0,
- cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1,
- cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2,
- cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }">
-
+ cellBlockNames="{ cb-0_0_0, cb-1_0_0, cb-0_1_0, cb-1_1_0, cb-0_0_1, cb-1_0_1, cb-0_1_1, cb-1_1_1, cb-0_0_2, cb-1_0_2, cb-0_1_2, cb-1_1_2, cb-0_0_3, cb-1_0_3, cb-0_1_3, cb-1_1_3 }">
-
-
+
+ referenceElevation="-0.01"/>
+
+
diff --git a/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp
index da7d3606fb2..83cf41e02f6 100644
--- a/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseMSWells.cpp
@@ -104,15 +104,20 @@ char const * xmlInput =
logLevel="2"
type="injector"
control="totalVolRate"
- referenceElevation="-0.01"
- targetBHP="1.45e7"
enableCrossflow="0"
useSurfaceConditions="1"
surfacePressure="1.45e7"
- surfaceTemperature="300.15"
- targetTotalRate="0.001"
- injectionTemperature="300.15"
- injectionStream="{ 1.0, 0.0 }"/>
+ surfaceTemperature="300.15">
+
+
+
@@ -580,6 +585,7 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ solver->wellSolver()->initializeWells( domain, time );
}
static real64 constexpr time = 0.0;
diff --git a/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp
index 277c7a2a38c..bf01638a399 100644
--- a/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testIsothermalReservoirCompositionalMultiphaseSSWells.cpp
@@ -104,15 +104,20 @@ char const * xmlInput =
logLevel="2"
type="injector"
control="totalVolRate"
- referenceElevation="-0.01"
- targetBHP="1.45e7"
enableCrossflow="0"
useSurfaceConditions="1"
surfacePressure="1.45e7"
- surfaceTemperature="300.15"
- targetTotalRate="0.001"
- injectionTemperature="300.15"
- injectionStream="{ 1.0, 0.0 }"/>
+ surfaceTemperature="300.15">
+
+
+
@@ -531,7 +536,6 @@ void testNumericalJacobian( CompositionalMultiphaseReservoirAndWells< Compositio
real64 const dP = perturbParameter * ( wellElemPressure[iwelem] + perturbParameter );
wellElemPressure.move( hostMemorySpace, true );
wellElemPressure[iwelem] += dP;
-
// after perturbing, update the pressure-dependent quantities in the well
wellSolver.updateState( domain );
@@ -652,6 +656,7 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ solver->wellSolver()->initializeWells( domain, time );
}
static real64 constexpr time = 0.0;
diff --git a/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp b/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp
index c45c9a21e68..5502909a7c5 100644
--- a/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testOpenClosePerf.cpp
@@ -61,13 +61,19 @@ char const * PreXmlInput =
logLevel="1"
targetRegions="{wellRegion1}"
useMass="0">
-
+
+
+
+
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp
index f1ca32e9e81..3ed0c30607e 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirCompositionalMultiphaseMSWells.cpp
@@ -61,21 +61,33 @@ char const * xmlInput =
logLevel="1"
targetRegions="{wellRegion1,wellRegion2}"
useMass="0">
-
-
+
+
+
+
+
+
+
+
@@ -483,6 +495,7 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ solver->wellSolver()->initializeWells( domain, time );
}
static real64 constexpr time = 0.0;
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp
index d75ad50a957..8fc88fd94ac 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirSinglePhaseMSWells.cpp
@@ -61,18 +61,31 @@ char const * PreXmlInput =
-
-
+
+
+
+
+
+
+
+
+
@@ -357,6 +370,8 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( TIME, DT, domain );
+
+ solver->wellSolver()->initializeWells( domain, TIME );
}
void TestAssembleCouplingTerms()
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp
index d10f1da56f6..5baf73b0430 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells.cpp
@@ -64,22 +64,35 @@ char const * PreXmlInput =
logLevel="1"
isThermal="1"
targetRegions="{wellRegion1,wellRegion2}">
-
-
+
+
+
+
+
+
+
+
+
@@ -515,6 +528,7 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( TIME, DT, domain );
+ solver->wellSolver()->initializeWells( domain, TIME );
}
void TestAssembleCouplingTerms()
diff --git a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp
index 255b0201692..07ccbe5626a 100644
--- a/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testReservoirThermalSinglePhaseMSWells_RateInj.cpp
@@ -79,19 +79,24 @@ char const * XmlInput =
isThermal="1"
writeCSV="1"
targetRegions="{ wellRegion2 }">
-
+
+ referenceElevation="-0.01"/>
+
+
@@ -597,6 +602,8 @@ class SinglePhaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( TIME, DT, domain );
+
+ solver->wellSolver()->initializeWells( domain, TIME );
}
void TestAssembleCouplingTerms()
diff --git a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp
index 98aa57a5c84..bd711598535 100644
--- a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseMSWells.cpp
@@ -108,15 +108,20 @@ char const * xmlInput =
logLevel="2"
type="injector"
control="totalVolRate"
- referenceElevation="-0.01"
- targetBHP="1.45e7"
enableCrossflow="0"
useSurfaceConditions="1"
surfacePressure="1.45e7"
- surfaceTemperature="300.15"
- targetTotalRate="0.001"
- injectionTemperature="300.15"
- injectionStream="{ 0.99, 0.01 }"/>
+ surfaceTemperature="300.15">
+
+
+
@@ -699,6 +704,7 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ solver->wellSolver()->initializeWells( domain, time );
}
static real64 constexpr time = 0.0;
diff --git a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp
index 76fa20d4cea..055682b1863 100644
--- a/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp
+++ b/src/coreComponents/integrationTests/wellsTests/testThermalReservoirCompositionalMultiphaseSSWells.cpp
@@ -109,15 +109,20 @@ char const * xmlInput =
logLevel="2"
type="injector"
control="totalVolRate"
- referenceElevation="-0.01"
- targetBHP="1.45e7"
enableCrossflow="0"
useSurfaceConditions="1"
surfacePressure="1.45e7"
- surfaceTemperature="300.15"
- targetTotalRate="0.001"
- injectionTemperature="300.15"
- injectionStream="{ 0.99, 0.01 }"/>
+ surfaceTemperature="300.15">
+
+
+
@@ -688,6 +693,7 @@ class CompositionalMultiphaseReservoirSolverTest : public ::testing::Test
solver->getSystemSolution() );
solver->implicitStepSetup( time, dt, domain );
+ solver->wellSolver()->initializeWells( domain, time );
}
static real64 constexpr time = 0.0;
diff --git a/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp b/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp
index a27d1a37a64..42eab7c568e 100644
--- a/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp
+++ b/src/coreComponents/linearAlgebra/utilities/ComponentMask.hpp
@@ -92,10 +92,10 @@ class ComponentMask
private:
/// Number of bits in mask storage
- static constexpr int NUM_BITS = internal::roundToNextPowerOfTwo( MAX_COMP );
+ static constexpr int NUM_BITS = geos::internal::roundToNextPowerOfTwo( MAX_COMP );
/// Type used to represent the bit mask
- using mask_t = typename internal::ComponentMaskType< NUM_BITS >::type;
+ using mask_t = typename geos::internal::ComponentMaskType< NUM_BITS >::type;
public:
diff --git a/src/coreComponents/mesh/WellElementSubRegion.hpp b/src/coreComponents/mesh/WellElementSubRegion.hpp
index 26089a42838..4be7cf48e3b 100644
--- a/src/coreComponents/mesh/WellElementSubRegion.hpp
+++ b/src/coreComponents/mesh/WellElementSubRegion.hpp
@@ -223,6 +223,14 @@ class WellElementSubRegion : public ElementSubRegionBase
m_topRank = rank;
}
+ /**
+ * @brief Get for the MPI rank that owns this well (i.e. the top segment).
+ * @return the rank that owns the top well element
+ */
+ int getTopRank() const
+ {
+ return m_topRank;
+ }
/**
* @brief Check if well is owned by current rank
* @return true if the well is owned by current rank, false otherwise
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
index 28ffa57e587..c7b51561083 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
+++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt
@@ -116,11 +116,21 @@ set( fluidFlowSolvers_headers
wells/SinglePhaseWellFields.hpp
wells/WellConstants.hpp
wells/WellControls.hpp
+ wells/WellConstraintsBase.hpp
+ wells/WellInjectionConstraint.hpp
+ wells/WellProductionConstraint.hpp
+ wells/WellBHPConstraints.hpp
+ wells/WellVolumeRateConstraint.hpp
+ wells/WellMassRateConstraint.hpp
+ wells/WellPhaseVolumeRateConstraint.hpp
+ wells/WellLiquidRateConstraint.hpp
wells/WellSolverBase.hpp
wells/WellSolverBaseFields.hpp
wells/LogLevelsInfo.hpp
wells/kernels/SinglePhaseWellKernels.hpp
wells/kernels/CompositionalMultiphaseWellKernels.hpp
+ wells/kernels/CompositionalMultiphaseWellConstraintKernels.hpp
+ wells/kernels/SinglePhaseWellConstraintKernels.hpp
proppantTransport/ProppantTransport.hpp
proppantTransport/ProppantTransportFields.hpp
proppantTransport/ProppantTransportKernels.hpp )
@@ -150,6 +160,14 @@ set( fluidFlowSolvers_sources
wells/SinglePhaseWell.cpp
wells/kernels/SinglePhaseWellKernels.cpp
wells/WellControls.cpp
+ wells/WellConstraintsBase.cpp
+ wells/WellInjectionConstraint.cpp
+ wells/WellProductionConstraint.cpp
+ wells/WellBHPConstraints.cpp
+ wells/WellVolumeRateConstraint.cpp
+ wells/WellMassRateConstraint.cpp
+ wells/WellPhaseVolumeRateConstraint.cpp
+ wells/WellLiquidRateConstraint.cpp
wells/WellSolverBase.cpp
proppantTransport/ProppantTransport.cpp
proppantTransport/ProppantTransportKernels.cpp )
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp
index 3b8184a1a38..61574270b4a 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp
@@ -50,6 +50,16 @@
#include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp"
#include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp"
+
+#include "physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellConstraintKernels.hpp"
+
+
+
#if defined( __INTEL_COMPILER )
#pragma GCC optimize "O0"
#endif
@@ -237,24 +247,13 @@ void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies )
WellControls & wellControls = getWellControls( subRegion );
wellControls.registerWrapper< real64 >( viewKeyStruct::currentBHPString() );
- wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentBHPString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0 >( m_numComponents + 2 ); // dP, dT, dC
-
wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::currentPhaseVolRateString() ).
setSizedFromParent( 0 ).
reference().resizeDimension< 0 >( m_numPhases );
- wellControls.registerWrapper< array2d< real64 > >( viewKeyStruct::dCurrentPhaseVolRateString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0, 1 >( m_numPhases, m_numComponents + 3 ); // dP, dT, dC, dQ
-
wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() );
wellControls.registerWrapper< real64 >( viewKeyStruct::currentTotalVolRateString() );
- wellControls.registerWrapper< array1d< real64 > >( viewKeyStruct::dCurrentTotalVolRateString() ).
- setSizedFromParent( 0 ).
- reference().resizeDimension< 0 >( m_numComponents + 3 ); // dP, dT, dC dQ
wellControls.registerWrapper< real64 >( viewKeyStruct::massDensityString() );
@@ -390,49 +389,14 @@ void CompositionalMultiphaseWell::validateConstitutiveModels( DomainPartition co
} );
}
-void CompositionalMultiphaseWell::validateInjectionStreams( WellElementSubRegion const & subRegion ) const
-{
- WellControls const & wellControls = getWellControls( subRegion );
-
- // check well injection stream for injectors
- if( wellControls.isInjector())
- {
- arrayView1d< real64 const > const & injectionStream = wellControls.getInjectionStream();
-
- integer const streamSize = injectionStream.size();
- GEOS_THROW_IF( ( streamSize == 0 ),
- "WellControls " << wellControls.getName() <<
- " : Injection stream not specified for well " << subRegion.getName(),
- InputError );
- GEOS_THROW_IF( ( streamSize != m_numComponents ),
- "WellControls " << wellControls.getName() <<
- " : Injection stream for well " << subRegion.getName() << " should have " <<
- m_numComponents << " components.",
- InputError );
- real64 compFracSum = 0;
- for( integer ic = 0; ic < m_numComponents; ++ic )
- {
- real64 const compFrac = injectionStream[ic];
- GEOS_THROW_IF( ( compFrac < 0.0 ) || ( compFrac > 1.0 ),
- "WellControls " << wellControls.getDataContext() <<
- ": Invalid injection stream for well " << subRegion.getName(),
- InputError, wellControls.getDataContext() );
- compFracSum += compFrac;
- }
- GEOS_THROW_IF( ( compFracSum < 1.0 - std::numeric_limits< real64 >::epsilon() ) ||
- ( compFracSum > 1.0 + std::numeric_limits< real64 >::epsilon() ),
- "WellControls " << wellControls.getDataContext() <<
- ": Invalid injection stream for well " << subRegion.getName(),
- InputError, wellControls.getDataContext() );
- }
-}
void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n,
real64 const & GEOS_UNUSED_PARAM( dt ),
WellElementSubRegion const & subRegion,
ElementRegionManager const & elemManager )
{
+ GEOS_UNUSED_VAR( time_n );
WellControls & wellControls = getWellControls( subRegion );
if( !wellControls.useSurfaceConditions() )
{
@@ -472,63 +436,14 @@ void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n
string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString());
MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
- WellControls::Control const currentControl = wellControls.getControl();
- real64 const & targetTotalRate = wellControls.getTargetTotalRate( time_n );
- real64 const & targetPhaseRate = wellControls.getTargetPhaseRate( time_n );
- real64 const & targetMassRate = wellControls.getTargetMassRate( time_n );
-
- GEOS_THROW_IF( wellControls.isInjector() && currentControl == WellControls::Control::PHASEVOLRATE,
- "WellControls " << wellControls.getDataContext() <<
- ": Phase rate control is not available for injectors",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && currentControl == WellControls::Control::TOTALVOLRATE,
- "WellControls " << wellControls.getDataContext() <<
- ": Total rate control is not available for producers",
- InputError, wellControls.getDataContext() );
-
- GEOS_THROW_IF( wellControls.isInjector() && targetTotalRate < 0.0,
- "WellControls " << wellControls.getDataContext() <<
- ": Target total rate cannot be negative for injectors",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isInjector() && !isZero( targetPhaseRate ),
- "WellControls " << wellControls.getDataContext() <<
- ": Target phase rate cannot be used for injectors",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && !isZero( targetTotalRate ),
- "WellControls " << wellControls.getDataContext() <<
- ": Target total rate cannot be used for producers",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && !isZero( targetMassRate ),
- "WellControls " << wellControls.getDataContext() <<
- ": Target mass rate cannot be used for producers",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( !m_useMass && !isZero( targetMassRate ),
- "WellControls " << wellControls.getDataContext() <<
- ": Target mass rate cannot with useMass=0",
- InputError, wellControls.getDataContext() );
-
- // The user always provides positive rates, but these rates are later multiplied by -1 internally for producers
- GEOS_THROW_IF( wellControls.isProducer() && targetPhaseRate > 0.0,
- "WellControls " << wellControls.getDataContext() <<
- ": Target phase rate cannot be negative for producers",
- InputError, wellControls.getDataContext() );
- GEOS_THROW_IF( wellControls.isProducer() && !isZero( targetTotalRate ),
- "WellControls " << wellControls.getDataContext() <<
- ": Target total rate cannot be used for producers",
- InputError, wellControls.getDataContext() );
-
- // Find target phase index for phase rate constraint
- for( integer ip = 0; ip < fluid.numFluidPhases(); ++ip )
- {
- if( fluid.phaseNames()[ip] == wellControls.getTargetPhaseName() )
- {
- m_targetPhaseIndex = ip;
- }
- }
- GEOS_THROW_IF( wellControls.isProducer() && m_targetPhaseIndex == -1,
- "WellControls " << wellControls.getDataContext() <<
- ": Phase " << wellControls.getTargetPhaseName() << " not found for well control " << wellControls.getName(),
- InputError, wellControls.getDataContext() );
+ // tjb
+ wellControls.forSubGroups< InjectionConstraint< PhaseVolumeRateConstraint >, ProductionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ constraint.validatePhaseType( fluid );
+ } );
+
+
+
}
void CompositionalMultiphaseWell::initializePostSubGroups()
@@ -539,16 +454,6 @@ void CompositionalMultiphaseWell::initializePostSubGroups()
validateConstitutiveModels( domain );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
- mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
- validateInjectionStreams( subRegion );
- } );
- } );
}
void CompositionalMultiphaseWell::initializePostInitialConditionsPreSubGroups()
@@ -567,6 +472,7 @@ void CompositionalMultiphaseWell::postRestartInitialization()
// loop over the wells
mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
WellElementSubRegion & subRegion )
+
{
// setup fluid separator
WellControls & wellControls = getWellControls( subRegion );
@@ -622,63 +528,35 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion &
{
return;
}
- using Deriv = constitutive::multifluid::DerivativeOffset;
- integer const numComp = m_numComponents;
localIndex const iwelemRef = subRegion.getTopWellElementIndex();
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
- integer const isThermal = fluid.isThermal();
// subRegion data
-
arrayView1d< real64 const > const & pres = subRegion.getField< well::pressure >();
-
arrayView1d< real64 > const & totalMassDens = subRegion.getField< well::totalMassDensity >();
- arrayView2d< real64, compflow::USD_FLUID_DC > const & dTotalMassDens = subRegion.getField< well::dTotalMassDensity >();
-
arrayView1d< real64 const > const wellElemGravCoef = subRegion.getField< well::gravityCoefficient >();
// control data
-
WellControls & wellControls = getWellControls( subRegion );
string const wellControlsName = wellControls.getName();
real64 const & refGravCoef = wellControls.getReferenceGravityCoef();
real64 & currentBHP =
wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
- arrayView1d< real64 > const & dCurrentBHP =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() );
- geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL )
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [ pres,
+ totalMassDens,
+ wellElemGravCoef,
+ ¤tBHP,
+ &iwelemRef,
+ &refGravCoef] ( localIndex const )
{
- integer constexpr IS_THERMAL = ISTHERMAL();
- GEOS_UNUSED_VAR( NC );
- // bring everything back to host, capture the scalars by reference
- forAll< serialPolicy >( 1, [&numComp,
- pres,
- totalMassDens,
- dTotalMassDens,
- wellElemGravCoef,
- ¤tBHP,
- &dCurrentBHP,
- &iwelemRef,
- &refGravCoef] ( localIndex const )
- {
- real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef];
- currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef;
- dCurrentBHP[Deriv::dP] = 1 + dTotalMassDens[iwelemRef][Deriv::dP] * diffGravCoef;
- for( integer ic = 0; ic < numComp; ++ic )
- {
- dCurrentBHP[Deriv::dC+ic] = dTotalMassDens[iwelemRef][Deriv::dC+ic] * diffGravCoef;
- }
- if constexpr ( IS_THERMAL )
- {
- dCurrentBHP[Deriv::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef;
- }
- } );
+ real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef];
+ currentBHP = pres[iwelemRef] + totalMassDens[iwelemRef] * diffGravCoef;
} );
+
GEOS_LOG_LEVEL_BY_RANK( logInfo::BoundaryConditions,
GEOS_FMT( "{}: BHP (at the specified reference elevation) = {} Pa",
wellControlsName, currentBHP ) );
@@ -695,8 +573,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg
return;
}
- integer constexpr maxNumComp = constitutive::MultiFluidBase::MAX_NUM_COMPONENTS;
- integer const numComp = m_numComponents;
+
integer const numPhase = m_numPhases;
localIndex const iwelemRef = subRegion.getTopWellElementIndex();
@@ -704,60 +581,110 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg
// subRegion data
- arrayView1d< real64 const > const & pres = subRegion.getField< well::pressure >();
- arrayView1d< real64 const > const & temp = subRegion.getField< well::temperature >();
arrayView1d< real64 const > const & connRate = subRegion.getField< well::mixtureConnectionRate >();
- arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< well::globalCompFraction >();
- arrayView3d< real64 const, compflow::USD_COMP_DC > const & dCompFrac_dCompDens = subRegion.getField< well::dGlobalCompFraction_dGlobalCompDensity >();
-
// fluid data
constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
- integer isThermal = fluidSeparator.isThermal();
- arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseFrac = fluidSeparator.phaseFraction();
- arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const & dPhaseFrac = fluidSeparator.dPhaseFraction();
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseFrac = fluidSeparator.phaseFraction();
arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & totalDens = fluidSeparator.totalDensity();
- arrayView3d< real64 const, constitutive::multifluid::USD_FLUID_DC > const & dTotalDens = fluidSeparator.dTotalDensity();
-
arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDens = fluidSeparator.phaseDensity();
- arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const & dPhaseDens = fluidSeparator.dPhaseDensity();
// control data
string const wellControlsName = wellControls.getName();
- bool const logSurfaceCondition = isLogLevelActive< logInfo::BoundaryConditions >( wellControls.getLogLevel());
- string const massUnit = m_useMass ? "kg" : "mol";
- integer const useSurfaceConditions = wellControls.useSurfaceConditions();
- real64 flashPressure;
- real64 flashTemperature;
- if( useSurfaceConditions )
- {
- // use surface conditions
- flashPressure = wellControls.getSurfacePressure();
- flashTemperature = wellControls.getSurfaceTemperature();
- }
- else
+ arrayView1d< real64 > const & currentPhaseVolRate =
+ wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
+
+ real64 & currentTotalVolRate =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+
+ real64 & currentMassRate =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() );
+
+ real64 & massDensity =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() );
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [&numPhase,
+ connRate,
+ totalDens,
+ phaseDens,
+ phaseFrac,
+ ¤tTotalVolRate,
+ currentPhaseVolRate,
+ ¤tMassRate,
+ &iwelemRef,
+ &massDensity] ( localIndex const )
{
- // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions
- flashPressure = wellControls.getRegionAveragePressure();
- if( flashPressure < 0.0 )
- {
- // region name not set, use segment conditions
- flashPressure = pres[iwelemRef];
- flashTemperature = temp[iwelemRef];
- }
- else
+ // Step 1: update the total volume rate
+
+ real64 const currentTotalRate = connRate[iwelemRef];
+ // Assumes useMass is true
+ currentMassRate = currentTotalRate;
+ // Step 1.1: compute the inverse of the total density and derivatives
+ massDensity = totalDens[iwelemRef][0];
+ real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0];
+
+ // Step 1.2: divide the total mass/molar rate by the total density to get the total volumetric rate
+ currentTotalVolRate = currentTotalRate * totalDensInv;
+
+ // Step 2: update the phase volume rate
+ for( integer ip = 0; ip < numPhase; ++ip )
{
- // use reservoir region averages
- flashTemperature = wellControls.getRegionAverageTemperature();
+ // Step 2.1: compute the inverse of the (phase density * phase fraction) and derivatives
+
+ // skip the rest of this function if phase ip is absent
+ bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0);
+ if( !phaseExists )
+ {
+ continue;
+ }
+
+ real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip];
+ real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv;
+
+ // Step 2.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate
+ currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv;
}
+ } );
+
+}
+
+void CompositionalMultiphaseWell::calculateReferenceElementRates( WellElementSubRegion & subRegion )
+{
+ GEOS_MARK_FUNCTION;
+
+ // the rank that owns the reference well element is responsible for the calculations below.
+ if( !subRegion.isLocallyOwned() )
+ {
+ return;
}
+
+ integer const numPhase = m_numPhases;
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+
+ WellControls & wellControls = getWellControls( subRegion );
+
+ // subRegion data
+ arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >();
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseFrac = fluidSeparator.phaseFraction();
+ arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & totalDens = fluidSeparator.totalDensity();
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDens = fluidSeparator.phaseDensity();
+
+ // control data
+ string const wellControlsName = wellControls.getName();
+ bool const logSurfaceCondition = isLogLevelActive< logInfo::BoundaryConditions >( wellControls.getLogLevel());
+ string const massUnit = m_useMass ? "kg" : "mol";
+
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+
arrayView1d< real64 > const & currentPhaseVolRate =
wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
- arrayView2d< real64 > const & dCurrentPhaseVolRate =
- wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() );
real64 & currentTotalVolRate =
wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
@@ -765,165 +692,84 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg
real64 & currentMassRate =
wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() );
- arrayView1d< real64 > const & dCurrentTotalVolRate =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() );
-
real64 & massDensity =
wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() );
+
constitutive::constitutiveUpdatePassThru( fluidSeparator, [&] ( auto & castedFluidSeparator )
{
// typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
typename TYPEOFREF( castedFluidSeparator ) ::KernelWrapper fluidSeparatorWrapper = castedFluidSeparator.createKernelWrapper();
- geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL )
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [fluidSeparatorWrapper,
+ &numPhase,
+ connRate,
+ totalDens,
+ phaseDens,
+ phaseFrac,
+ logSurfaceCondition,
+ &useSurfaceConditions,
+ ¤tTotalVolRate,
+ currentPhaseVolRate,
+ ¤tMassRate,
+ &iwelemRef,
+ &wellControlsName,
+ &massUnit,
+ &massDensity] ( localIndex const )
{
- integer constexpr NUM_COMP = NC();
- integer constexpr IS_THERMAL = ISTHERMAL();
- using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NUM_COMP, IS_THERMAL >;
- // bring everything back to host, capture the scalars by reference
- forAll< serialPolicy >( 1, [&numComp,
- &numPhase,
- fluidSeparatorWrapper,
- pres,
- temp,
- compFrac,
- dCompFrac_dCompDens,
- connRate,
- totalDens,
- dTotalDens,
- phaseDens,
- dPhaseDens,
- phaseFrac,
- dPhaseFrac,
- logSurfaceCondition,
- &useSurfaceConditions,
- &flashPressure,
- &flashTemperature,
- ¤tTotalVolRate,
- dCurrentTotalVolRate,
- currentPhaseVolRate,
- dCurrentPhaseVolRate,
- ¤tMassRate,
- &iwelemRef,
- &wellControlsName,
- &massUnit,
- &massDensity] ( localIndex const )
- {
- GEOS_UNUSED_VAR( massUnit );
- using Deriv = constitutive::multifluid::DerivativeOffset;
- stackArray1d< real64, maxNumComp > work( numComp );
- // Step 1: evaluate the phase and total density in the reference element
-
- // We need to evaluate the density as follows:
- // - Surface conditions: using the surface pressure provided by the user
- // - Segment conditions: using the pressure in the top element
- // - Reservoir conditions: using the average region pressure
- if( useSurfaceConditions )
- {
- // we need to compute the surface density
- fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure, flashTemperature, compFrac[iwelemRef] );
- if( logSurfaceCondition )
- {
- GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa and T_surface = {} K",
- wellControlsName, flashPressure, flashTemperature ) );
- }
-#ifdef GEOS_USE_HIP
- GEOS_UNUSED_VAR( wellControlsName );
-#endif
+ GEOS_UNUSED_VAR( massUnit );
- }
- else
- {
- fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure, flashTemperature, compFrac[iwelemRef] );
- }
- // Step 2: update the total volume rate
- real64 const currentTotalRate = connRate[iwelemRef];
- // Assumes useMass is true
- currentMassRate = currentTotalRate;
- // Step 2.1: compute the inverse of the total density and derivatives
- massDensity = totalDens[iwelemRef][0];
- real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0];
+ // Step 2: update the total volume rate
- stackArray1d< real64, maxNumComp > dTotalDensInv_dCompDens( numComp );
- for( integer ic = 0; ic < numComp; ++ic )
- {
- dTotalDensInv_dCompDens[ic] = -dTotalDens[iwelemRef][0][Deriv::dC+ic] * totalDensInv * totalDensInv;
- }
- applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], dTotalDensInv_dCompDens, work.data() );
-
- // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate
- currentTotalVolRate = currentTotalRate * totalDensInv;
- // Compute derivatives dP dT
- real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv;
- dCurrentTotalVolRate[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres;
- if constexpr ( IS_THERMAL )
- {
- dCurrentTotalVolRate[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv;
- }
+ real64 const currentTotalRate = connRate[iwelemRef];
+ // Assumes useMass is true
+ currentMassRate = currentTotalRate;
+ // Step 2.1: compute the inverse of the total density
+ massDensity = totalDens[iwelemRef][0];
+ real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0];
- if( logSurfaceCondition && useSurfaceConditions )
- {
- GEOS_LOG_RANK( GEOS_FMT( "{}: total fluid density at surface conditions = {} {}/sm3, total rate = {} {}/s, total surface volumetric rate = {} sm3/s",
- wellControlsName, totalDens[iwelemRef][0], massUnit, connRate[iwelemRef], massUnit, currentTotalVolRate ) );
- }
- dCurrentTotalVolRate[COFFSET_WJ::dQ] = totalDensInv;
- for( integer ic = 0; ic < numComp; ++ic )
- {
- dCurrentTotalVolRate[COFFSET_WJ::dC+ic] = currentTotalRate * dTotalDensInv_dCompDens[ic];
- }
+ // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate
+ currentTotalVolRate = currentTotalRate * totalDensInv;
- // Step 3: update the phase volume rate
- for( integer ip = 0; ip < numPhase; ++ip )
- {
- // Step 3.1: compute the inverse of the (phase density * phase fraction) and derivatives
+ if( logSurfaceCondition && useSurfaceConditions )
+ {
+ GEOS_LOG_RANK( GEOS_FMT( "{}: total fluid density at surface conditions = {} {}/sm3, total rate = {} {}/s, total surface volumetric rate = {} sm3/s",
+ wellControlsName, totalDens[iwelemRef][0], massUnit, connRate[iwelemRef], massUnit, currentTotalVolRate ) );
+ }
- // skip the rest of this function if phase ip is absent
- bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0);
- if( !phaseExists )
- {
- continue;
- }
+ // Step 3: update the phase volume rate
+ for( integer ip = 0; ip < numPhase; ++ip )
+ {
- real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip];
- real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv;
- real64 const dPhaseFracTimesPhaseDensInv_dPres = dPhaseFrac[iwelemRef][0][ip][Deriv::dP] * phaseDensInv
- - dPhaseDens[iwelemRef][0][ip][Deriv::dP] * phaseFracTimesPhaseDensInv * phaseDensInv;
+ // Step 3.1: compute the inverse of the (phase density * phase fraction)
+ // skip the rest of this function if phase ip is absent
+ bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0);
+ if( !phaseExists )
+ {
+ continue;
+ }
- // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate
- currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv;
- dCurrentPhaseVolRate[ip][COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres;
- dCurrentPhaseVolRate[ip][COFFSET_WJ::dQ] = phaseFracTimesPhaseDensInv;
- if constexpr (IS_THERMAL )
- {
- real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv
- - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv;
- dCurrentPhaseVolRate[ip][COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp;
- }
+ real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip];
+ real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv;
- for( integer ic = 0; ic < numComp; ++ic )
- {
- dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv;
- dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv;
- dCurrentPhaseVolRate[ip][COFFSET_WJ::dC+ic] *= currentTotalRate;
- }
- applyChainRuleInPlace( numComp, dCompFrac_dCompDens[iwelemRef], &dCurrentPhaseVolRate[ip][COFFSET_WJ::dC], work.data() );
+ // Step 3.2: divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate
+ currentPhaseVolRate[ip] = currentTotalRate * phaseFracTimesPhaseDensInv;
- if( logSurfaceCondition && useSurfaceConditions )
- {
- GEOS_LOG_RANK( GEOS_FMT( "{}: density of phase {} at surface conditions = {} {}/sm3, phase surface volumetric rate = {} sm3/s",
- wellControlsName, ip, phaseDens[iwelemRef][0][ip], massUnit, currentPhaseVolRate[ip] ) );
- }
+ if( logSurfaceCondition && useSurfaceConditions )
+ {
+ GEOS_LOG_RANK( GEOS_FMT( "{}: density of phase {} at surface conditions = {} {}/sm3, phase surface volumetric rate = {} sm3/s",
+ wellControlsName, ip, phaseDens[iwelemRef][0][ip], massUnit, currentPhaseVolRate[ip] ) );
}
- } );
+ }
} );
} );
}
-
void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRegion )
{
GEOS_MARK_FUNCTION;
@@ -950,70 +796,181 @@ void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRe
}
-real64 CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const
+void CompositionalMultiphaseWell::updateSeparator( WellElementSubRegion & subRegion )
{
GEOS_MARK_FUNCTION;
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+ // the rank that owns the reference well element is responsible for the calculations below.
+ if( !subRegion.isLocallyOwned() )
+ {
+ return;
+ }
- real64 maxDeltaPhaseVolFrac =
- m_isThermal ?
- thermalCompositionalMultiphaseBaseKernels::
- PhaseVolumeFractionKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
- m_numPhases,
- subRegion,
- fluid )
-: isothermalCompositionalMultiphaseBaseKernels::
- PhaseVolumeFractionKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
- m_numPhases,
- subRegion,
- fluid );
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
- return maxDeltaPhaseVolFrac;
-}
+ WellControls & wellControls = getWellControls( subRegion );
-void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & subRegion ) const
-{
- GEOS_MARK_FUNCTION;
+ // subRegion data
+ arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >();
+ arrayView1d< real64 const > const & temp = subRegion.getField< fields::well::temperature >();
+ arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >();
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
- fluid.isThermal() ?
- thermalCompositionalMultiphaseWellKernels::
- TotalMassDensityKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
- m_numPhases,
- subRegion,
- fluid )
- :
- compositionalMultiphaseWellKernels::
- TotalMassDensityKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
- m_numPhases,
- subRegion,
- fluid );
-}
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
-void CompositionalMultiphaseWell::updateState( DomainPartition & domain )
-{
- GEOS_MARK_FUNCTION;
+ // control data
- real64 maxPhaseVolFrac = 0.0;
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
- mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
- WellElementSubRegion & subRegion )
- {
+ string const wellControlsName = wellControls.getName();
+ bool const logSurfaceCondition = isLogLevelActive< logInfo::BoundaryConditions >( wellControls.getLogLevel());
+ string const massUnit = m_useMass ? "kg" : "mol";
+
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+ real64 flashPressure;
+ real64 flashTemperature;
+ if( useSurfaceConditions )
+ {
+ // use surface conditions
+ flashPressure = wellControls.getSurfacePressure();
+ flashTemperature = wellControls.getSurfaceTemperature();
+ }
+ else
+ {
+ // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions
+ flashPressure = wellControls.getRegionAveragePressure();
+ if( flashPressure < 0.0 )
+ {
+ // region name not set, use segment conditions
+ flashPressure = pres[iwelemRef];
+ flashTemperature = temp[iwelemRef];
+ }
+ else
+ {
+ // use reservoir region averages
+ flashTemperature = wellControls.getRegionAverageTemperature();
+ }
+ }
+
+ constitutive::constitutiveUpdatePassThru( fluidSeparator, [&] ( auto & castedFluidSeparator )
+ {
+ // typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+ typename TYPEOFREF( castedFluidSeparator ) ::KernelWrapper fluidSeparatorWrapper = castedFluidSeparator.createKernelWrapper();
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [fluidSeparatorWrapper,
+ wellControlsName,
+ useSurfaceConditions,
+ flashPressure,
+ flashTemperature,
+ logSurfaceCondition,
+ iwelemRef,
+ pres,
+ temp,
+ compFrac] ( localIndex const )
+ {
+ // - Surface conditions: using the surface pressure provided by the user
+ // - Reservoir conditions: using the pressure in the top element
+ if( useSurfaceConditions )
+ {
+ // we need to compute the surface density
+ //fluidWrapper.update( iwelemRef, 0, surfacePres, surfaceTemp, compFrac[iwelemRef] );
+ fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure, flashTemperature, compFrac[iwelemRef] );
+ if( logSurfaceCondition )
+ {
+ GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa and T_surface = {} K",
+ wellControlsName, flashPressure, flashTemperature ) );
+ }
+#ifdef GEOS_USE_HIP
+ GEOS_UNUSED_VAR( wellControlsName );
+#endif
+ }
+ else
+ {
+ fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure, flashTemperature, compFrac[iwelemRef] );
+ }
+ } );
+ } );
+}
+
+
+real64 CompositionalMultiphaseWell::updatePhaseVolumeFraction( WellElementSubRegion & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+
+ real64 maxDeltaPhaseVolFrac =
+ m_isThermal ?
+ thermalCompositionalMultiphaseBaseKernels::
+ PhaseVolumeFractionKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ subRegion,
+ fluid )
+: isothermalCompositionalMultiphaseBaseKernels::
+ PhaseVolumeFractionKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ subRegion,
+ fluid );
+
+ return maxDeltaPhaseVolFrac;
+}
+
+void CompositionalMultiphaseWell::updateTotalMassDensity( WellElementSubRegion & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+ fluid.isThermal() ?
+ thermalCompositionalMultiphaseWellKernels::
+ TotalMassDensityKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ subRegion,
+ fluid )
+ :
+ compositionalMultiphaseWellKernels::
+ TotalMassDensityKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ subRegion,
+ fluid );
+
+}
+
+real64 CompositionalMultiphaseWell::updateWellState( WellElementSubRegion & subRegion )
+{
+ GEOS_MARK_FUNCTION;
+
+ real64 maxPhaseVolFrac = updateSubRegionState( subRegion );
+
+ return maxPhaseVolFrac;
+
+}
+
+void CompositionalMultiphaseWell::updateState( DomainPartition & domain )
+{
+ GEOS_MARK_FUNCTION;
+ //tjb
+ real64 maxPhaseVolFrac = 0.0;
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
WellControls & wellControls = getWellControls( subRegion );
- if( wellControls.getWellStatus() == WellControls::Status::OPEN )
+ if( wellControls.getWellState())
{
+#if 1
+ real64 const maxRegionPhaseVolFrac = updateWellState( subRegion );
+#else
real64 const maxRegionPhaseVolFrac = updateSubRegionState( subRegion );
+
+#endif
maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac );
}
} );
@@ -1028,30 +985,279 @@ void CompositionalMultiphaseWell::updateState( DomainPartition & domain )
real64 CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion )
{
- // update properties
- updateGlobalComponentFraction( subRegion );
+ real64 maxPhaseVolChange=0.0;
+ WellControls & wellControls = getWellControls( subRegion );
+ if( wellControls.getWellState())
+ {
+ if( m_useNewCode )
+ {
+ // update properties
+ updateGlobalComponentFraction( subRegion );
+
+ // update densities, phase fractions, phase volume fractions
- // update volumetric rates for the well constraints
- // note: this must be called before updateFluidModel
- updateVolRatesForConstraint( subRegion );
+ updateFluidModel( subRegion ); // Calculate fluid properties
- // update densities, phase fractions, phase volume fractions
+ updateSeparator( subRegion ); // Calculate fluid properties at control conditions
- updateFluidModel( subRegion ); // Calculate fluid properties;
- real64 maxPhaseVolChange = updatePhaseVolumeFraction( subRegion );
- updateTotalMassDensity( subRegion );
- // update the current BHP pressure
- updateBHPForConstraint( subRegion );
+ updateVolRatesForConstraint( subRegion ); // remove tjb ??
+
+ maxPhaseVolChange = updatePhaseVolumeFraction( subRegion );
+ updateTotalMassDensity( subRegion );
+
+ // Calculate the reference element rates
+ calculateReferenceElementRates( subRegion );
+
+ // update the current BHP
+ updateBHPForConstraint( subRegion );
+
+ // Broad case the updated well state to other ranks
+ real64 & currentBHP =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
+ array1d< real64 > currentPhaseVolRate =
+ wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
+ real64 & currentTotalVolRate =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+ real64 & currentMassRate =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() );
+ integer topRank = subRegion.getTopRank();
+ MpiWrapper::broadcast( currentBHP, topRank );
+ MpiWrapper::bcast( currentPhaseVolRate.data(), LvArray::integerConversion< int >( currentPhaseVolRate.size() ), topRank );
+ MpiWrapper::broadcast( currentTotalVolRate, topRank );
+ MpiWrapper::broadcast( currentMassRate, topRank );
+ if( !subRegion.isLocallyOwned() )
+ {
+ wellControls.getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) =currentPhaseVolRate;
+
+
+ }
+ }
+ else
+ {
+ // update properties
+ updateGlobalComponentFraction( subRegion );
+
+ // update volumetric rates for the well constraints
+ // note: this must be called before updateFluidModel
+
+ updateVolRatesForConstraint( subRegion );
+
+ // update densities, phase fractions, phase volume fractions
+
+ updateFluidModel( subRegion ); // Calculate fluid properties;
+ maxPhaseVolChange = updatePhaseVolumeFraction( subRegion );
+ updateTotalMassDensity( subRegion );
+ // update the current BHP pressure
+ updateBHPForConstraint( subRegion );
+ }
+
+ }
return maxPhaseVolChange;
}
-void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, real64 const & time_n )
+void CompositionalMultiphaseWell::initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n )
{
GEOS_MARK_FUNCTION;
-
+ GEOS_UNUSED_VAR( domain );
integer const numComp = m_numComponents;
integer const numPhase = m_numPhases;
+ m_nextDt = -1;
+ // TODO: change the way we access the flowSolver here
+ CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
+
+
+ compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::CompFlowAccessors
+ resCompFlowAccessors( mesh.getElemManager(), flowSolver.getName() );
+ compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::MultiFluidAccessors
+ resMultiFluidAccessors( mesh.getElemManager(), flowSolver.getName() );
+
+ WellControls & wellControls = getWellControls( subRegion );
+ PerforationData const & perforationData = *subRegion.getPerforationData();
+ arrayView2d< real64 const > const compPerfRate = perforationData.getField< fields::well::compPerforationRate >();
+
+ bool const hasNonZeroRate = MpiWrapper::max< integer >( hasNonZero( compPerfRate ));
+
+ if( time_n <= 0.0 || ( wellControls.isWellOpen( ) && !hasNonZeroRate ) )
+ {
+ wellControls.setWellState( true );
+ if( wellControls.getCurrentConstraint() == nullptr )
+ {
+ // tjb needed for backward compatibility. and these 2 lists must be consistent
+ ConstraintTypeId inputControl = ConstraintTypeId( wellControls.getInputControl());
+ if( wellControls.isProducer() )
+ {
+ wellControls.forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( constraint.getControl() == inputControl )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ wellControls.setControl( static_cast< WellControls::Control >(inputControl) ); // tjb old
+ }
+
+ } );
+ }
+ else
+ {
+
+ wellControls.forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >,
+ InjectionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( constraint.getControl() == inputControl )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ wellControls.setControl( static_cast< WellControls::Control >(inputControl) ); // tjb old
+ }
+ } );
+ }
+ }
+ // get well primary variables on well elements
+ arrayView1d< real64 > const & wellElemPressure = subRegion.getField< well::pressure >();
+ arrayView1d< real64 > const & wellElemTemp = subRegion.getField< well::temperature >();
+ arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = subRegion.getField< well::globalCompDensity >();
+ arrayView1d< real64 > const & connRate = subRegion.getField< well::mixtureConnectionRate >();
+
+ // get the info stored on well elements
+ arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< well::globalCompFraction >();
+ arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< well::gravityCoefficient >();
+
+ // get the element region, subregion, index
+ arrayView1d< localIndex const > const resElementRegion = perforationData.getField< perforation::reservoirElementRegion >();
+ arrayView1d< localIndex const > const resElementSubRegion = perforationData.getField< perforation::reservoirElementSubRegion >();
+ arrayView1d< localIndex const > const resElementIndex = perforationData.getField< perforation::reservoirElementIndex >();
+
+ arrayView1d< real64 const > const & perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >();
+ arrayView1d< integer const > const & perfStatus = perforationData.getField< fields::perforation::perforationStatus >();
+
+ // 1) Loop over all perforations to compute an average mixture density and component fraction
+ // 2) Initialize the reference pressure
+ // 3) Estimate the pressures in the well elements using the average density
+ compositionalMultiphaseWellKernels::
+ PresTempCompFracInitializationKernel::
+ launch( perforationData.size(),
+ subRegion.size(),
+ numComp,
+ numPhase,
+ wellControls,
+ 0.0, // initialization done at t = 0
+ resCompFlowAccessors.get( flow::pressure{} ),
+ resCompFlowAccessors.get( flow::temperature{} ),
+ resCompFlowAccessors.get( flow::globalCompDensity{} ),
+ resCompFlowAccessors.get( flow::phaseVolumeFraction{} ),
+ resMultiFluidAccessors.get( fields::multifluid::phaseMassDensity{} ),
+ resElementRegion,
+ resElementSubRegion,
+ resElementIndex,
+ perfGravCoef,
+ perfStatus,
+ wellElemGravCoef,
+ wellElemPressure,
+ wellElemTemp,
+ wellElemCompFrac );
+
+ // get well secondary variables on well elements
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity();
+ arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & wellElemTotalDens = fluid.totalDensity();
+
+ // 4) Back calculate component densities
+ constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid )
+ {
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+
+ thermalCompositionalMultiphaseBaseKernels::
+ FluidUpdateKernel::
+ launch< serialPolicy >( subRegion.size(),
+ fluidWrapper,
+ wellElemPressure,
+ wellElemTemp,
+ wellElemCompFrac );
+ } );
+
+ compositionalMultiphaseWellKernels::
+ CompDensInitializationKernel::launch( subRegion.size(),
+ numComp,
+ wellElemCompFrac,
+ wellElemTotalDens,
+ wellElemCompDens );
+
+ // 5) Recompute the pressure-dependent properties
+ updateSubRegionState( subRegion );
+
+ // 6) Estimate the well rates
+ // TODO: initialize rates using perforation rates
+ compositionalMultiphaseWellKernels::
+ RateInitializationKernel::
+ launch( subRegion.size(),
+ wellControls,
+ time_n, // initialization done at time_n
+ wellElemPhaseDens,
+ wellElemTotalDens,
+ connRate );
+
+ updateVolRatesForConstraint( subRegion );
+ // Since this is a well manager class the rates need to be pushed into the WellControls class, which represnets the well
+ WellConstraintBase * constraint = wellControls.getCurrentConstraint();
+ constraint->setBHP ( wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setPhaseVolumeRates ( wellControls.getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) );
+ constraint->setTotalVolumeRate ( wellControls.getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ));
+ constraint->setMassRate( wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() ));
+ // 7) Copy well / fluid dofs to "prop"_n variables
+ saveState( subRegion );
+ }
+ else if( !hasNonZeroRate )
+ {
+ wellControls.setWellState( false );
+ GEOS_LOG_RANK_0( "tjb shut wells "<< subRegion.getName());
+ }
+ else
+ {
+ wellControls.setWellState( true );
+ // setup if restart
+ if( wellControls.getCurrentConstraint() == nullptr )
+ {
+ updateSubRegionState( subRegion );
+ if( wellControls.isProducer() )
+ {
+ wellControls.forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ & constraint )
+ {
+ if( ConstraintTypeId( wellControls.getControl()) == constraint.getControl() )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ }
+ } );
+ }
+ else
+ {
+ wellControls.forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >, InjectionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ &
+ constraint )
+ {
+ if( ConstraintTypeId( wellControls.getControl()) == constraint.getControl() )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ }
+ } );
+ }
+ }
+
+ }
+}
+
+
+void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, real64 const & time_n )
+{
+ GEOS_MARK_FUNCTION;
+ m_nextDt = -1;
// TODO: change the way we access the flowSolver here
CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
@@ -1071,103 +1277,68 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea
[&]( localIndex const,
WellElementSubRegion & subRegion )
{
- WellControls & wellControls = getWellControls( subRegion );
- PerforationData const & perforationData = *subRegion.getPerforationData();
- arrayView2d< real64 const > const compPerfRate = perforationData.getField< fields::well::compPerforationRate >();
- bool const hasNonZeroRate = MpiWrapper::max< integer >( hasNonZero( compPerfRate ));
+ initializeWell( domain, mesh, subRegion, time_n );
+ } );
- if( wellControls.isWellOpen() && !hasNonZeroRate )
- {
- // get well primary variables on well elements
- arrayView1d< real64 > const & wellElemPressure = subRegion.getField< well::pressure >();
- arrayView1d< real64 > const & wellElemTemp = subRegion.getField< well::temperature >();
- arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens = subRegion.getField< well::globalCompDensity >();
- arrayView1d< real64 > const & connRate = subRegion.getField< well::mixtureConnectionRate >();
-
- // get the info stored on well elements
- arrayView2d< real64, compflow::USD_COMP > const & wellElemCompFrac = subRegion.getField< well::globalCompFraction >();
- arrayView1d< real64 const > const & wellElemGravCoef = subRegion.getField< well::gravityCoefficient >();
-
- // get the element region, subregion, index
- arrayView1d< localIndex const > const resElementRegion = perforationData.getField< perforation::reservoirElementRegion >();
- arrayView1d< localIndex const > const resElementSubRegion = perforationData.getField< perforation::reservoirElementSubRegion >();
- arrayView1d< localIndex const > const resElementIndex = perforationData.getField< perforation::reservoirElementIndex >();
-
- arrayView1d< real64 const > const & perfGravCoef = perforationData.getField< fields::well::gravityCoefficient >();
- arrayView1d< integer const > const & perfStatus = perforationData.getField< fields::perforation::perforationStatus >();
-
- // 1) Loop over all perforations to compute an average mixture density and component fraction
- // 2) Initialize the reference pressure
- // 3) Estimate the pressures in the well elements using the average density
- compositionalMultiphaseWellKernels::
- PresTempCompFracInitializationKernel::
- launch( perforationData.size(),
- subRegion.size(),
- numComp,
- numPhase,
- wellControls,
- 0.0, // initialization done at t = 0
- resCompFlowAccessors.get( flow::pressure{} ),
- resCompFlowAccessors.get( flow::temperature{} ),
- resCompFlowAccessors.get( flow::globalCompDensity{} ),
- resCompFlowAccessors.get( flow::phaseVolumeFraction{} ),
- resMultiFluidAccessors.get( fields::multifluid::phaseMassDensity{} ),
- resElementRegion,
- resElementSubRegion,
- resElementIndex,
- perfGravCoef,
- perfStatus,
- wellElemGravCoef,
- wellElemPressure,
- wellElemTemp,
- wellElemCompFrac );
-
- // get well secondary variables on well elements
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
- arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & wellElemPhaseDens = fluid.phaseDensity();
- arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & wellElemTotalDens = fluid.totalDensity();
+ } );
+}
- // 4) Back calculate component densities
- constitutive::constitutiveUpdatePassThru( fluid, [&] ( auto & castedFluid )
- {
- typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
-
- thermalCompositionalMultiphaseBaseKernels::
- FluidUpdateKernel::
- launch< serialPolicy >( subRegion.size(),
- fluidWrapper,
- wellElemPressure,
- wellElemTemp,
- wellElemCompFrac );
- } );
+void CompositionalMultiphaseWell::assembleWellFluxTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+ GEOS_UNUSED_VAR( time );
- compositionalMultiphaseWellKernels::
- CompDensInitializationKernel::launch( subRegion.size(),
- numComp,
- wellElemCompFrac,
- wellElemTotalDens,
- wellElemCompDens );
+ BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags;
+ if( m_useTotalMassEquation )
+ kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation );
- // 5) Recompute the pressure-dependent properties
- updateSubRegionState( subRegion );
+ string const wellDofKey = dofManager.getKey( wellElementDofName());
+
+ WellControls const & well_controls = getWellControls( subRegion );
+ if( well_controls.isWellOpen( ) && !m_keepVariablesConstantDuringInitStep )
+ {
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString());
+ MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ int numComponents = fluid.numFluidComponents();
+
+ if( isThermal() )
+ {
+ thermalCompositionalMultiphaseWellKernels::
+ FaceBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ dt,
+ dofManager.rankOffset(),
+ kernelFlags,
+ wellDofKey,
+ well_controls,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ compositionalMultiphaseWellKernels::
+ FaceBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ dt,
+ dofManager.rankOffset(),
+ kernelFlags,
+ wellDofKey,
+ well_controls,
+ subRegion,
+ localMatrix,
+ localRhs );
+ }
+ }
- // 6) Estimate the well rates
- // TODO: initialize rates using perforation rates
- compositionalMultiphaseWellKernels::
- RateInitializationKernel::
- launch( subRegion.size(),
- m_targetPhaseIndex,
- wellControls,
- time_n, // initialization done at time_n
- wellElemPhaseDens,
- wellElemTotalDens,
- connRate );
- }
- } );
- } );
}
void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time,
@@ -1193,43 +1364,9 @@ void CompositionalMultiphaseWell::assembleFluxTerms( real64 const & time,
[&]( localIndex const,
WellElementSubRegion & subRegion )
{
- WellControls const & well_controls = getWellControls( subRegion );
- if( well_controls.getWellStatus() == WellControls::Status::OPEN && !m_keepVariablesConstantDuringInitStep )
- {
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString());
- MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
- int const numComponents = fluid.numFluidComponents();
- if( isThermal() )
- {
- thermalCompositionalMultiphaseWellKernels::
- FaceBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( numComponents,
- dt,
- dofManager.rankOffset(),
- kernelFlags,
- wellDofKey,
- well_controls,
- subRegion,
- fluid,
- localMatrix,
- localRhs );
- }
- else
- {
- compositionalMultiphaseWellKernels::
- FaceBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( numComponents,
- dt,
- dofManager.rankOffset(),
- kernelFlags,
- wellDofKey,
- well_controls,
- subRegion,
- localMatrix,
- localRhs );
- }
- }
+ assembleWellFluxTerms( time, dt, subRegion, dofManager, localMatrix, localRhs );
+
} );
} );
@@ -1246,119 +1383,271 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time
GEOS_UNUSED_VAR( time );
GEOS_UNUSED_VAR( dt );
- BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags;
- if( m_useTotalMassEquation )
- kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation );
+ BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags;
+ if( m_useTotalMassEquation )
+ kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation );
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+
+ assembleWellAccumulationTerms( time, dt, subRegion, dofManager, localMatrix, localRhs );
+ } );
+ } );
+
+
+}
+
+void CompositionalMultiphaseWell::assembleWellAccumulationTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+ GEOS_UNUSED_VAR( time );
+ GEOS_UNUSED_VAR( dt );
+
+ BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags;
+ if( m_useTotalMassEquation )
+ kernelFlags.set( isothermalCompositionalMultiphaseBaseKernels::KernelFlags::TotalMassEquation );
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString());
+ MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ integer const numPhases = fluid.numFluidPhases();
+ integer const numComponents = fluid.numFluidComponents();
+ WellControls & wellControls = getWellControls( subRegion );
+ if( wellControls.getWellStatus() == WellControls::Status::OPEN && !m_keepVariablesConstantDuringInitStep )
+ {
+ if( isThermal() )
+ {
+
+ thermalCompositionalMultiphaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ numPhases,
+ wellControls.isProducer(),
+ dofManager.rankOffset(),
+ kernelFlags,
+ wellDofKey,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ compositionalMultiphaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( numComponents,
+ numPhases,
+ wellControls.isProducer(),
+ dofManager.rankOffset(),
+ kernelFlags,
+ wellDofKey,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ // get the degrees of freedom and ghosting info
+ arrayView1d< globalIndex const > const & wellElemDofNumber =
+ subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank();
+ arrayView1d< integer const > const elemStatus = subRegion.getLocalWellElementStatus();
+ arrayView1d< real64 > const mixConnRate = subRegion.getField< fields::well::mixtureConnectionRate >();
+ localIndex rank_offset = dofManager.rankOffset();
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ if( wellElemGhostRank[ei] < 0 )
+ {
+ if( elemStatus[ei]==WellElementSubRegion::WellElemStatus::CLOSED )
+ {
+ mixConnRate[ei] = 0.0;
+ globalIndex const dofIndex = wellElemDofNumber[ei];
+ localIndex const localRow = dofIndex - rank_offset;
+
+ real64 const unity = 1.0;
+ for( integer i=0; i < m_numDofPerWellElement; i++ )
+ {
+ globalIndex const rindex = localRow+i;
+ globalIndex const cindex =dofIndex + i;
+ localMatrix.template addToRow< serialAtomic >( rindex,
+ &cindex,
+ &unity,
+ 1 );
+ localRhs[rindex] = 0.0;
+ }
+ }
+ }
+ } );
+
+ }
+ else
+ {
+ arrayView1d< globalIndex const > const & wellElemDofNumber =
+ subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank();
+
+ arrayView1d< real64 > mixConnRate = subRegion.getField< fields::well::mixtureConnectionRate >();
+ localIndex rank_offset = dofManager.rankOffset();
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
+ {
+ if( wellElemGhostRank[ei] < 0 )
+ {
+ mixConnRate[ei] = 0.0;
+ globalIndex const dofIndex = wellElemDofNumber[ei];
+ localIndex const localRow = dofIndex - rank_offset;
+
+ real64 const unity = 1.0;
+ for( integer i=0; i < m_numDofPerWellElement; i++ )
+ {
+ globalIndex const rindex = localRow+i;
+ globalIndex const cindex =dofIndex + i;
+ localMatrix.template addToRow< serialAtomic >( rindex,
+ &cindex,
+ &unity,
+ 1 );
+ localRhs[rindex] = 0.0;
+ }
+ }
+ } );
+ // zero out current state constraint quantities
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() )=0.0;
+ wellControls.getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ).zero();
+ wellControls.getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() )=0.0;
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() )=0.0;
+ }
+}
+
+
+real64
+CompositionalMultiphaseWell::calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+ integer numNorm = 1; // mass balance
+ array1d< real64 > localResidualNorm;
+ array1d< real64 > localResidualNormalizer;
+
+ if( isThermal() )
+ {
+ numNorm = 2; // mass balance and energy balance
+ }
+ localResidualNorm.resize( numNorm );
+ localResidualNormalizer.resize( numNorm );
+
+ globalIndex const rankOffset = dofManager.rankOffset();
string const wellDofKey = dofManager.getKey( wellElementDofName() );
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+
+
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName );
+
+ WellControls const & wellControls = getWellControls( subRegion );
+
+ if( wellControls.isWellOpen( ) )
{
- mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames,
- [&]( localIndex const,
- WellElementSubRegion & subRegion )
+ // step 1: compute the norm in the subRegion
+ if( isThermal() )
{
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString());
- MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
- integer const numPhases = fluid.numFluidPhases();
- integer const numComponents = fluid.numFluidComponents();
- WellControls const & wellControls = getWellControls( subRegion );
- if( wellControls.getWellStatus() == WellControls::Status::OPEN && !m_keepVariablesConstantDuringInitStep )
+ real64 subRegionResidualNorm[2]{};
+
+ thermalCompositionalMultiphaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ for( integer i=0; i >( numComponents,
- numPhases,
- wellControls.isProducer(),
- dofManager.rankOffset(),
- kernelFlags,
- wellDofKey,
- subRegion,
- fluid,
- localMatrix,
- localRhs );
- }
- else
+ if( subRegionResidualNorm[i] > localResidualNorm[i] )
{
- compositionalMultiphaseWellKernels::
- ElementBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( numComponents,
- numPhases,
- wellControls.isProducer(),
- dofManager.rankOffset(),
- kernelFlags,
- wellDofKey,
- subRegion,
- fluid,
- localMatrix,
- localRhs );
+ localResidualNorm[i] = subRegionResidualNorm[i];
}
- // get the degrees of freedom and ghosting info
- arrayView1d< globalIndex const > const & wellElemDofNumber =
- subRegion.getReference< array1d< globalIndex > >( wellDofKey );
- arrayView1d< integer const > const wellElemGhostRank = subRegion.ghostRank();
- arrayView1d< integer const > const elemStatus = subRegion.getLocalWellElementStatus();
- arrayView1d< real64 > const mixConnRate = subRegion.getField< fields::well::mixtureConnectionRate >();
- localIndex rank_offset = dofManager.rankOffset();
- forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
- {
- if( wellElemGhostRank[ei] < 0 )
- {
- if( elemStatus[ei]==WellElementSubRegion::WellElemStatus::CLOSED )
- {
- mixConnRate[ei] = 0.0;
- globalIndex const dofIndex = wellElemDofNumber[ei];
- localIndex const localRow = dofIndex - rank_offset;
-
- real64 const unity = 1.0;
- for( integer i=0; i < m_numDofPerWellElement; i++ )
- {
- globalIndex const rindex = localRow+i;
- globalIndex const cindex =dofIndex + i;
- localMatrix.template addToRow< serialAtomic >( rindex,
- &cindex,
- &unity,
- 1 );
- localRhs[rindex] = 0.0;
- }
- }
- }
- } );
}
- else
- {
- // get the degrees of freedom and ghosting info
- arrayView1d< globalIndex const > const & wellElemDofNumber =
- subRegion.getReference< array1d< globalIndex > >( wellDofKey );
- arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank();
- localIndex rank_offset = dofManager.rankOffset();
- forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const ei )
- {
- if( wellElemGhostRank[ei] < 0 )
- {
- globalIndex const dofIndex = wellElemDofNumber[ei];
- localIndex const localRow = dofIndex - rank_offset;
- real64 unity = 1.0;
- for( integer i=0; i < m_numDofPerWellElement; i++ )
- {
- globalIndex const rindex = localRow+i;
- globalIndex const cindex =dofIndex + i;
- localMatrix.template addToRow< serialAtomic >( rindex,
- &cindex,
- &unity,
- 1 );
- localRhs[rindex] = 0.0;
- }
- }
- } );
+ }
+ else
+ {
+ real64 subRegionResidualNorm[1]{};
+ compositionalMultiphaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ numDofPerWellElement(),
+ rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+
+
+
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ if( subRegionResidualNorm[0] > localResidualNorm[0] )
+ {
+ localResidualNorm[0] = subRegionResidualNorm[0];
}
- } ); // forElementSubRegions
- } ); // forDiscretizationOnMeshTargets
+ }
+ }
+ else
+ {
+ for( integer i=0; i >( m_numComponents,
- m_targetPhaseIndex,
- rankOffset,
- wellDofKey,
- localRhs,
- subRegion,
- fluid,
- wellControls,
- time_n,
- dt,
- m_nonlinearSolverParameters.m_minNormalizer,
- subRegionResidualNorm );
- // step 2: reduction across meshBodies/regions/subRegions
+ thermalCompositionalMultiphaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+ // step 2: reduction across meshBodies/regions/subRegions
- for( integer i=0; i localResidualNorm[i] )
+ for( integer i=0; i localResidualNorm[i] )
+ {
+ localResidualNorm[i] = subRegionResidualNorm[i];
+ }
}
- }
- }
- else
- {
- real64 subRegionResidualNorm[1]{};
- compositionalMultiphaseWellKernels::ResidualNormKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
- numDofPerWellElement(),
- m_targetPhaseIndex,
- rankOffset,
- wellDofKey,
- localRhs,
- subRegion,
- fluid,
- wellControls,
- time_n,
- dt,
- m_nonlinearSolverParameters.m_minNormalizer,
- subRegionResidualNorm );
+ }
+ else
+ {
+ real64 subRegionResidualNorm[1]{};
+ compositionalMultiphaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ numDofPerWellElement(),
+ rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
- // step 2: reduction across meshBodies/regions/subRegions
+ // step 2: reduction across meshBodies/regions/subRegions
- if( subRegionResidualNorm[0] > localResidualNorm[0] )
+ if( subRegionResidualNorm[0] > localResidualNorm[0] )
+ {
+ localResidualNorm[0] = subRegionResidualNorm[0];
+ }
+ }
+ }
+ else
+ {
+ for( integer i=0; i const & localSolution )
+{
+ GEOS_MARK_FUNCTION;
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+ real64 scalingFactor = 1.0;
+ real64 maxDeltaPres = 0.0, maxDeltaCompDens = 0.0, maxDeltaTemp = 0.0;
+ real64 minPresScalingFactor = 1.0, minCompDensScalingFactor = 1.0, minTempScalingFactor = 1.0;
+
+ arrayView1d< real64 const > const pressure = subRegion.getField< fields::well::pressure >();
+ arrayView1d< real64 const > const temperature = subRegion.getField< fields::well::temperature >();
+ arrayView2d< real64 const, compflow::USD_COMP > const compDens = subRegion.getField< fields::well::globalCompDensity >();
+ arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >();
+ arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >();
+ arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >();
+ const integer temperatureOffset = m_numComponents+2;
+ auto const subRegionData =
+ m_isThermal
+ ? thermalCompositionalMultiphaseBaseKernels::
+ SolutionScalingKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange,
+ m_maxAbsolutePresChange,
+ m_maxRelativeTempChange,
+ m_maxCompFracChange,
+ m_maxRelativeCompDensChange,
+ pressure,
+ temperature,
+ compDens,
+ pressureScalingFactor,
+ compDensScalingFactor,
+ temperatureScalingFactor,
+ dofManager.rankOffset(),
+ m_numComponents,
+ wellDofKey,
+ subRegion,
+ localSolution,
+ temperatureOffset )
+ : isothermalCompositionalMultiphaseBaseKernels::
+ SolutionScalingKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_maxRelativePresChange,
+ m_maxAbsolutePresChange,
+ m_maxCompFracChange,
+ m_maxRelativeCompDensChange,
+ pressure,
+ compDens,
+ pressureScalingFactor,
+ compDensScalingFactor,
+ dofManager.rankOffset(),
+ m_numComponents,
+ wellDofKey,
+ subRegion,
+ localSolution );
+
+
+ scalingFactor = std::min( subRegionData.localMinVal, scalingFactor );
+
+ maxDeltaPres = std::max( maxDeltaPres, subRegionData.localMaxDeltaPres );
+ maxDeltaCompDens = std::max( maxDeltaCompDens, subRegionData.localMaxDeltaCompDens );
+ maxDeltaTemp = std::max( maxDeltaTemp, subRegionData.localMaxDeltaTemp );
+ minPresScalingFactor = std::min( minPresScalingFactor, subRegionData.localMinPresScalingFactor );
+ minCompDensScalingFactor = std::min( minCompDensScalingFactor, subRegionData.localMinCompDensScalingFactor );
+ minTempScalingFactor = std::min( minTempScalingFactor, subRegionData.localMinTempScalingFactor );
+
+
+ scalingFactor = MpiWrapper::min( scalingFactor );
+ maxDeltaPres = MpiWrapper::max( maxDeltaPres );
+ maxDeltaCompDens = MpiWrapper::max( maxDeltaCompDens );
+ minPresScalingFactor = MpiWrapper::min( minPresScalingFactor );
+ minCompDensScalingFactor = MpiWrapper::min( minCompDensScalingFactor );
+
+ string const massUnit = m_useMass ? "kg/m3" : "mol/m3";
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Max well pressure change: {} Pa (before scaling)",
+ getName(), GEOS_FMT( "{:.{}f}", maxDeltaPres, 3 ) ) );
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Max well component density change: {} {} (before scaling)",
+ getName(), GEOS_FMT( "{:.{}f}", maxDeltaCompDens, 3 ), massUnit ) );
+
+ if( m_isThermal )
+ {
+ maxDeltaTemp = MpiWrapper::max( maxDeltaTemp );
+ minTempScalingFactor = MpiWrapper::min( minTempScalingFactor );
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Max well temperature change: {} K (before scaling)",
+ getName(), GEOS_FMT( "{:.{}f}", maxDeltaTemp, 3 ) ) );
+ }
+
+
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Min well pressure scaling factor: {}",
+ getName(), minPresScalingFactor ) );
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Min well component density scaling factor: {}",
+ getName(), minCompDensScalingFactor ) );
+ if( m_isThermal )
+ {
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Min well temperature scaling factor: {}",
+ getName(), minTempScalingFactor ) );
+ }
+
+
+ return LvArray::math::max( scalingFactor, m_minScalingFactor );
+
+}
+
real64
CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain,
DofManager const & dofManager,
@@ -1611,186 +2018,303 @@ CompositionalMultiphaseWell::scalingForSystemSolution( DomainPartition & domain,
}
bool
-CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain,
- DofManager const & dofManager,
- arrayView1d< real64 const > const & localSolution,
- real64 const scalingFactor )
+CompositionalMultiphaseWell::checkWellSystemSolution( ElementSubRegionBase & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor )
{
GEOS_MARK_FUNCTION;
string const wellDofKey = dofManager.getKey( wellElementDofName() );
integer localCheck = 1;
+
+
real64 minPres = 0.0, minDens = 0.0, minTotalDens = 0.0;
integer numNegPres = 0, numNegDens = 0, numNegTotalDens = 0;
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
- {
- mesh.getElemManager().forElementSubRegions( regionNames,
- [&]( localIndex const,
- ElementSubRegionBase & subRegion )
- {
- //integer const m_allowCompDensChopping(true);
- integer const m_allowNegativePressure( false );
- compositionalMultiphaseUtilities::ScalingType const m_scalingType( compositionalMultiphaseUtilities::ScalingType::Global );
- arrayView1d< real64 const > const pressure =
- subRegion.getField< well::pressure >();
- arrayView1d< real64 const > const temperature =
- subRegion.getField< well::temperature >();
- arrayView2d< real64 const, compflow::USD_COMP > const compDens =
- subRegion.getField< well::globalCompDensity >();
- arrayView1d< real64 > pressureScalingFactor = subRegion.getField< well::pressureScalingFactor >();
- arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< well::temperatureScalingFactor >();
- arrayView1d< real64 > compDensScalingFactor = subRegion.getField< well::globalCompDensityScalingFactor >();
-
- // check that pressure and component densities are non-negative
- // for thermal, check that temperature is above 273.15 K
- const integer temperatureOffset = m_numComponents+2;
- auto const subRegionData =
- m_isThermal
+ const std::string wellName = subRegion.getName();
+
+ //integer const m_allowCompDensChopping(true);
+ integer const m_allowNegativePressure( false );
+ compositionalMultiphaseUtilities::ScalingType const m_scalingType( compositionalMultiphaseUtilities::ScalingType::Global );
+ arrayView1d< real64 const > const pressure =
+ subRegion.getField< fields::well::pressure >();
+ arrayView1d< real64 const > const temperature =
+ subRegion.getField< fields::well::temperature >();
+ arrayView2d< real64 const, compflow::USD_COMP > const compDens =
+ subRegion.getField< fields::well::globalCompDensity >();
+ arrayView1d< real64 > pressureScalingFactor = subRegion.getField< fields::well::pressureScalingFactor >();
+ arrayView1d< real64 > temperatureScalingFactor = subRegion.getField< fields::well::temperatureScalingFactor >();
+ arrayView1d< real64 > compDensScalingFactor = subRegion.getField< fields::well::globalCompDensityScalingFactor >();
+
+ // check that pressure and component densities are non-negative
+ // for thermal, check that temperature is above 273.15 K
+ const integer temperatureOffset = m_numComponents+2;
+ auto const subRegionData =
+ m_isThermal
? thermalCompositionalMultiphaseBaseKernels::
- SolutionCheckKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping,
- m_allowNegativePressure,
- m_scalingType,
- scalingFactor,
- pressure,
- temperature,
- compDens,
- pressureScalingFactor,
- temperatureScalingFactor,
- compDensScalingFactor,
- dofManager.rankOffset(),
- m_numComponents,
- wellDofKey,
- subRegion,
- localSolution,
- temperatureOffset )
+ SolutionCheckKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping,
+ m_allowNegativePressure,
+ m_scalingType,
+ scalingFactor,
+ pressure,
+ temperature,
+ compDens,
+ pressureScalingFactor,
+ temperatureScalingFactor,
+ compDensScalingFactor,
+ dofManager.rankOffset(),
+ m_numComponents,
+ wellDofKey,
+ subRegion,
+ localSolution,
+ temperatureOffset )
: isothermalCompositionalMultiphaseBaseKernels::
- SolutionCheckKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping,
- m_allowNegativePressure,
- m_scalingType,
- scalingFactor,
- pressure,
- compDens,
- pressureScalingFactor,
- compDensScalingFactor,
- dofManager.rankOffset(),
- m_numComponents,
- wellDofKey,
- subRegion,
- localSolution );
+ SolutionCheckKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_allowCompDensChopping,
+ m_allowNegativePressure,
+ m_scalingType,
+ scalingFactor,
+ pressure,
+ compDens,
+ pressureScalingFactor,
+ compDensScalingFactor,
+ dofManager.rankOffset(),
+ m_numComponents,
+ wellDofKey,
+ subRegion,
+ localSolution );
+
+ localCheck = std::min( localCheck, subRegionData.localMinVal );
+
+ minPres = std::min( minPres, subRegionData.localMinPres );
+ minDens = std::min( minDens, subRegionData.localMinDens );
+ minTotalDens = std::min( minTotalDens, subRegionData.localMinTotalDens );
+ numNegPres += subRegionData.localNumNegPressures;
+ numNegDens += subRegionData.localNumNegDens;
+ numNegTotalDens += subRegionData.localNumNegTotalDens;
+
+
+ minPres = MpiWrapper::min( minPres );
+ minDens = MpiWrapper::min( minDens );
+ minTotalDens = MpiWrapper::min( minTotalDens );
+ numNegPres = MpiWrapper::sum( numNegPres );
+ numNegDens = MpiWrapper::sum( numNegDens );
+ numNegTotalDens = MpiWrapper::sum( numNegTotalDens );
+
+ if( numNegPres > 0 )
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Number of negative well pressure values: {}, minimum value: {} Pa",
+ subRegion.getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) );
+ string const massUnit = m_useMass ? "kg/m3" : "mol/m3";
+ if( numNegDens > 0 )
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Number of negative well component density values: {}, minimum value: {} {} ",
+ subRegion.getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) );
+ if( minTotalDens > 0 )
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Number of negative total well density values: {}, minimum value: {} {} ",
+ subRegion.getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) );
+
+
+
+ return MpiWrapper::min( localCheck );
+}
+
+bool
+CompositionalMultiphaseWell::checkSystemSolution( DomainPartition & domain,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor )
+{
+ GEOS_MARK_FUNCTION;
- localCheck = std::min( localCheck, subRegionData.localMinVal );
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ integer globalCheck = 1;
- minPres = std::min( minPres, subRegionData.localMinPres );
- minDens = std::min( minDens, subRegionData.localMinDens );
- minTotalDens = std::min( minTotalDens, subRegionData.localMinTotalDens );
- numNegPres += subRegionData.localNumNegPressures;
- numNegDens += subRegionData.localNumNegDens;
- numNegTotalDens += subRegionData.localNumNegTotalDens;
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions( regionNames,
+ [&]( localIndex const,
+ ElementSubRegionBase & subRegion )
+ {
+ integer localCheck = checkWellSystemSolution( subRegion, dofManager, localSolution, scalingFactor );
+ globalCheck = MpiWrapper::min( localCheck );
} );
} );
+ return globalCheck;
+}
- minPres = MpiWrapper::min( minPres );
- minDens = MpiWrapper::min( minDens );
- minTotalDens = MpiWrapper::min( minTotalDens );
- numNegPres = MpiWrapper::sum( numNegPres );
- numNegDens = MpiWrapper::sum( numNegDens );
- numNegTotalDens = MpiWrapper::sum( numNegTotalDens );
+void CompositionalMultiphaseWell::computeWellPerforationRates( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager const & elemManager,
+ WellElementSubRegion & subRegion )
+{
+ GEOS_MARK_FUNCTION;
+ GEOS_UNUSED_VAR( time_n );
+
+ CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
+
+ PerforationData * const perforationData = subRegion.getPerforationData();
+ WellControls const & wellControls = getWellControls( subRegion );
+ if( wellControls.isWellOpen() && !m_keepVariablesConstantDuringInitStep )
+ {
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ bool isThermal = fluid.isThermal();
+
+ if( isThermal )
+ {
+ thermalPerforationFluxKernels::
+ PerforationFluxKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ flowSolver.getName(),
+ perforationData,
+ subRegion,
+ fluid,
+ elemManager,
+ wellControls.isInjector(),
+ wellControls.isCrossflowEnabled());
+ }
+ else
+ {
+ isothermalPerforationFluxKernels::
+ PerforationFluxKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
+ m_numPhases,
+ flowSolver.getName(),
+ perforationData,
+ subRegion,
+ elemManager,
+ wellControls.isInjector(),
+ wellControls.isCrossflowEnabled() );
+ }
+ }
+ else
+ {
+// Zero completion flow rate
+ arrayView2d< real64 > const compPerfRate = perforationData->getField< fields::well::compPerforationRate >();
+ for( integer iperf=0; iperfsize(); iperf++ )
+ {
+ for( integer ic = 0; ic < m_numComponents; ++ic )
+ {
+ compPerfRate[iperf][ic] = 0.0;
+ }
+ }
+ }
- if( numNegPres > 0 )
- GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
- GEOS_FMT( " {}: Number of negative well pressure values: {}, minimum value: {} Pa",
- getName(), numNegPres, fmt::format( "{:.{}f}", minPres, 3 ) ) );
- string const massUnit = m_useMass ? "kg/m3" : "mol/m3";
- if( numNegDens > 0 )
- GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
- GEOS_FMT( " {}: Number of negative well component density values: {}, minimum value: {} {} ",
- getName(), numNegDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) );
- if( minTotalDens > 0 )
- GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
- GEOS_FMT( " {}: Number of negative total well density values: {}, minimum value: {} {} ",
- getName(), minTotalDens, fmt::format( "{:.{}f}", minDens, 3 ), massUnit ) );
- return MpiWrapper::min( localCheck );
}
+
void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n,
- real64 const & GEOS_UNUSED_PARAM( dt ),
+ real64 const & dt,
DomainPartition & domain )
{
GEOS_MARK_FUNCTION;
- GEOS_UNUSED_VAR( time_n );
-
- forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & mesh,
- string_array const & regionNames )
+ GEOS_UNUSED_VAR( dt );
+ forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
{
// TODO: change the way we access the flowSolver here
- CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() );
+
ElementRegionManager & elemManager = mesh.getElemManager();
elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
WellElementSubRegion & subRegion )
{
- PerforationData * const perforationData = subRegion.getPerforationData();
- WellControls const & wellControls = getWellControls( subRegion );
- if( wellControls.getWellStatus() == WellControls::Status::OPEN && !m_keepVariablesConstantDuringInitStep )
- {
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
- bool const isThermal = fluid.isThermal();
+ computeWellPerforationRates( time_n, dt, elemManager, subRegion );
- if( isThermal )
- {
- thermalPerforationFluxKernels::
- PerforationFluxKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
- m_numPhases,
- flowSolver.getName(),
- perforationData,
- subRegion,
- fluid,
- elemManager,
- wellControls.isInjector(),
- wellControls.isCrossflowEnabled() );
- }
- else
- {
- isothermalPerforationFluxKernels::
- PerforationFluxKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( m_numComponents,
- m_numPhases,
- flowSolver.getName(),
- perforationData,
- subRegion,
- elemManager,
- wellControls.isInjector(),
- wellControls.isCrossflowEnabled() );
- }
- }
- else
- {
- // Zero completion flow rate
- arrayView2d< real64 > const compPerfRate = perforationData->getField< well::compPerforationRate >();
- for( integer iperf=0; iperfsize(); iperf++ )
- {
- for( integer ic = 0; ic < m_numComponents; ++ic )
- {
- compPerfRate[iperf][ic] = 0.0;
- }
- }
- }
} );
} );
}
+void
+CompositionalMultiphaseWell::applyWellSystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ WellElementSubRegion & subRegion )
+{
+
+ GEOS_UNUSED_VAR( domain );
+ DofManager::CompMask pressureMask( m_numDofPerWellElement, 0, 1 );
+ DofManager::CompMask componentMask( m_numDofPerWellElement, 1, numFluidComponents()+1 );
+ DofManager::CompMask connRateMask( m_numDofPerWellElement, numFluidComponents()+1, numFluidComponents()+2 );
+ GEOS_UNUSED_VAR( dt );
+ // update all the fields using the global damping coefficients
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ fields::well::pressure::key(),
+ scalingFactor,
+ pressureMask );
+
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ fields::well::globalCompDensity::key(),
+ scalingFactor,
+ componentMask );
+
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ fields::well::mixtureConnectionRate::key(),
+ scalingFactor,
+ connRateMask );
+
+ if( isThermal() )
+ {
+ DofManager::CompMask temperatureMask( m_numDofPerWellElement, numFluidComponents()+2, numFluidComponents()+3 );
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ fields::well::temperature::key(),
+ scalingFactor,
+ temperatureMask );
+
+ }
+
+#if 1
+ // if component density chopping is allowed, some component densities may be negative after the update
+ // these negative component densities are set to zero in this function
+ if( m_allowCompDensChopping )
+ {
+ chopNegativeDensities( subRegion );
+ }
+#endif
+
+ // synchronize
+ FieldIdentifiers fieldsToBeSync;
+ if( isThermal() )
+ {
+ fieldsToBeSync.addElementFields( { fields::well::pressure::key(),
+ fields::well::globalCompDensity::key(),
+ fields::well::mixtureConnectionRate::key(),
+ fields::well::temperature::key() },
+ getTargetRegionNames() );
+ }
+ else
+ {
+ fieldsToBeSync.addElementFields( { fields::well::pressure::key(),
+ fields::well::globalCompDensity::key(),
+ fields::well::mixtureConnectionRate::key() },
+ getTargetRegionNames() );
+ }
+ CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync,
+ mesh,
+ domain.getNeighbors(),
+ true );
+
+}
void
CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager,
@@ -1872,6 +2396,34 @@ CompositionalMultiphaseWell::applySystemSolution( DofManager const & dofManager,
}
+void CompositionalMultiphaseWell::chopNegativeDensities( WellElementSubRegion & subRegion )
+{
+ integer const numComp = m_numComponents;
+
+
+ arrayView1d< integer const > const & wellElemGhostRank = subRegion.ghostRank();
+
+ arrayView2d< real64, compflow::USD_COMP > const & wellElemCompDens =
+ subRegion.getField< fields::well::globalCompDensity >();
+
+ forAll< parallelDevicePolicy<> >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ if( wellElemGhostRank[iwelem] < 0 )
+ {
+ for( integer ic = 0; ic < numComp; ++ic )
+ {
+ // we allowed for some densities to be slightly negative in CheckSystemSolution
+ // if the new density is negative, chop back to zero
+ if( wellElemCompDens[iwelem][ic] < 0 )
+ {
+ wellElemCompDens[iwelem][ic] = 0.0;
+ }
+ }
+ }
+ } );
+
+}
+
void CompositionalMultiphaseWell::chopNegativeDensities( DomainPartition & domain )
{
integer const numComp = m_numComponents;
@@ -1963,15 +2515,158 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition &
} );
}
+void CompositionalMultiphaseWell::assembleWellConstraintTerms( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+
+ // the rank that owns the reference well element is responsible for the calculations below.
+ if( !subRegion.isLocallyOwned() )
+ {
+ return;
+ }
+ WellControls & wellControls = getWellControls( subRegion );
+
+ if( wellControls.isProducer() )
+ {
+ wellControls.forSubGroups< MinimumBHPConstraint, ProductionConstraint< PhaseVolumeRateConstraint >, ProductionConstraint< MassRateConstraint >, ProductionConstraint< VolumeRateConstraint >,
+ ProductionConstraint< LiquidRateConstraint >
+ >( [&]( auto & constraint )
+ {
+ if( constraint.getName() == wellControls.getCurrentConstraint()->getName())
+ {
+ // found limiting constraint
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
+ integer isThermal = fluidSeparator.isThermal();
+ integer const numComp = fluidSeparator.numFluidComponents();
+ geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL )
+ {
+ integer constexpr NUM_COMP = NC();
+ integer constexpr IS_THERMAL = ISTHERMAL();
+
+ wellConstraintKernels::ConstraintHelper< NUM_COMP, IS_THERMAL >::assembleConstraintEquation( time_n,
+ wellControls,
+ constraint,
+ subRegion,
+ dofManager.getKey( wellElementDofName() ),
+ dofManager.rankOffset(),
+ localMatrix,
+ localRhs );
+ } );
+ }
+ } );
+ }
+ else
+ {
+ wellControls.forSubGroups< MaximumBHPConstraint, InjectionConstraint< PhaseVolumeRateConstraint >, InjectionConstraint< MassRateConstraint >,
+ InjectionConstraint< VolumeRateConstraint >,
+ InjectionConstraint< LiquidRateConstraint >
+ >( [&]( auto & constraint )
+ {
+ if( constraint.getName() == wellControls.getCurrentConstraint()->getName())
+ {
+ // found limiting constraint
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
+ integer isThermal = fluidSeparator.isThermal();
+ integer const numComp = fluidSeparator.numFluidComponents();
+ geos::internal::kernelLaunchSelectorCompThermSwitch( numComp, isThermal, [&] ( auto NC, auto ISTHERMAL )
+ {
+ integer constexpr NUM_COMP = NC();
+ integer constexpr IS_THERMAL = ISTHERMAL();
+
+ wellConstraintKernels::ConstraintHelper< NUM_COMP, IS_THERMAL >::assembleConstraintEquation( time_n,
+ wellControls,
+ constraint,
+ subRegion,
+ dofManager.getKey( wellElementDofName() ),
+ dofManager.rankOffset(),
+ localMatrix,
+ localRhs );
+ } );
+ }
+ } );
+ }
+}
+
+void CompositionalMultiphaseWell::assembleWellPressureRelations( real64 const & GEOS_UNUSED_PARAM( time_n ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+
+ WellControls & wellControls = getWellControls( subRegion );
+
+ if( wellControls.isWellOpen( ) && !m_keepVariablesConstantDuringInitStep )
+ {
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ bool const isThermal = fluid.isThermal();
+ // get the degrees of freedom, depth info, next welem index
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ arrayView1d< globalIndex const > const & wellElemDofNumber =
+ subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & wellElemGravCoef =
+ subRegion.getField< well::gravityCoefficient >();
+ arrayView1d< localIndex const > const & nextWellElemIndex =
+ subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() );
+
+ // get primary variables on well elements
+ arrayView1d< real64 const > const & wellElemPres =
+ subRegion.getField< well::pressure >();
+
+ // get total mass density on well elements (for potential calculations)
+ arrayView1d< real64 const > const & wellElemTotalMassDens =
+ subRegion.getField< well::totalMassDensity >();
+ arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens =
+ subRegion.getField< well::dTotalMassDensity >();
+
+ // segment status
+ arrayView1d< integer const > const elemStatus =subRegion.getLocalWellElementStatus();
+
+ bool controlHasSwitched = false;
+ isothermalCompositionalMultiphaseBaseKernels::
+ KernelLaunchSelectorCompTherm< compositionalMultiphaseWellKernels::PressureRelationKernel >
+ ( numFluidComponents(),
+ isThermal,
+ subRegion.size(),
+ dofManager.rankOffset(),
+ elemStatus,
+ wellElemDofNumber,
+ wellElemGravCoef,
+ nextWellElemIndex,
+ wellElemPres,
+ wellElemTotalMassDens,
+ dWellElemTotalMassDens,
+ controlHasSwitched,
+ localMatrix,
+ localRhs );
+
+ }
+
+}
+
void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time_n,
- real64 const & GEOS_UNUSED_PARAM( dt ),
+ real64 const & dt,
DomainPartition const & domain,
DofManager const & dofManager,
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
GEOS_MARK_FUNCTION;
-
+ GEOS_UNUSED_PARAM( dt )
forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &,
MeshLevel const & mesh,
string_array const & regionNames )
@@ -1984,109 +2679,57 @@ void CompositionalMultiphaseWell::assemblePressureRelations( real64 const & time
WellElementSubRegion const & subRegion )
{
- WellControls & wellControls = getWellControls( subRegion );
+ assembleWellPressureRelations( time_n, dt, subRegion, dofManager, localMatrix, localRhs );
+ } );
+ } );
- if( wellControls.isWellOpen( ) && !m_keepVariablesConstantDuringInitStep )
- {
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
- bool const isThermal = fluid.isThermal();
- // get the degrees of freedom, depth info, next welem index
- string const wellDofKey = dofManager.getKey( wellElementDofName() );
- arrayView1d< globalIndex const > const & wellElemDofNumber =
- subRegion.getReference< array1d< globalIndex > >( wellDofKey );
- arrayView1d< real64 const > const & wellElemGravCoef =
- subRegion.getField< well::gravityCoefficient >();
- arrayView1d< localIndex const > const & nextWellElemIndex =
- subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() );
-
- // get primary variables on well elements
- arrayView1d< real64 const > const & wellElemPres =
- subRegion.getField< well::pressure >();
-
- // get total mass density on well elements (for potential calculations)
- arrayView1d< real64 const > const & wellElemTotalMassDens =
- subRegion.getField< well::totalMassDensity >();
- arrayView2d< real64 const, compflow::USD_FLUID_DC > const & dWellElemTotalMassDens =
- subRegion.getField< well::dTotalMassDensity >();
-
- // segment status
- arrayView1d< integer const > const elemStatus =subRegion.getLocalWellElementStatus();
-
- bool controlHasSwitched = false;
- isothermalCompositionalMultiphaseBaseKernels::
- KernelLaunchSelectorCompTherm< compositionalMultiphaseWellKernels::PressureRelationKernel >
- ( numFluidComponents(),
- isThermal,
- subRegion.size(),
- dofManager.rankOffset(),
- subRegion.isLocallyOwned(),
- subRegion.getTopWellElementIndex(),
- m_targetPhaseIndex,
- wellControls,
- time_n, // controls evaluated with BHP/rate of the beginning of step
- elemStatus,
- wellElemDofNumber,
- wellElemGravCoef,
- nextWellElemIndex,
- wellElemPres,
- wellElemTotalMassDens,
- dWellElemTotalMassDens,
- controlHasSwitched,
- localMatrix,
- localRhs );
-
- if( controlHasSwitched )
- {
- // TODO: move the switch logic into wellControls
- // TODO: implement a more general switch when more then two constraints per well type are allowed
+}
- if( wellControls.getControl() == WellControls::Control::BHP )
- {
- if( wellControls.isProducer() )
- {
- wellControls.switchToPhaseRateControl( wellControls.getTargetPhaseRate( time_n ) );
- GEOS_LOG_LEVEL_RANK_0( logInfo::WellControl,
- GEOS_FMT( "Control switch for well {} from BHP constraint to phase volumetric rate constraint", subRegion.getName() ) );
- }
- else if( wellControls.getInputControl() == WellControls::Control::MASSRATE )
- {
- wellControls.switchToMassRateControl( wellControls.getTargetMassRate( time_n ) );
- GEOS_LOG_LEVEL_RANK_0( logInfo::WellControl,
- GEOS_FMT( "Control switch for well {} from BHP constraint to mass rate constraint", subRegion.getName()) );
- }
- else
- {
- wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( time_n ) );
- GEOS_LOG_LEVEL_RANK_0( logInfo::WellControl,
- GEOS_FMT( "Control switch for well {} from BHP constraint to total volumetric rate constraint", subRegion.getName()) );
- }
- }
- else
- {
- wellControls.switchToBHPControl( wellControls.getTargetBHP( time_n ) );
- GEOS_LOG_LEVEL_RANK_0( logInfo::WellControl,
- GEOS_FMT( "Control switch for well {} from rate constraint to BHP constraint", subRegion.getName() ) );
- }
- }
+void CompositionalMultiphaseWell::saveState( WellElementSubRegion & subRegion )
+{
- // If a well is opened and then timestep is cut resulting in the well being shut, if the well is opened
- // the well initialization code requires control type to by synced
- integer owner = -1;
- // Only subregion owner evaluates well control and control changes need to be broadcast to all ranks
- if( subRegion.isLocallyOwned() )
- {
- owner = MpiWrapper::commRank( MPI_COMM_GEOS );
- }
- owner = MpiWrapper::max( owner );
- WellControls::Control wellControl = wellControls.getControl();
- MpiWrapper::broadcast( wellControl, owner );
- wellControls.setControl( wellControl );
- }
+ // get a reference to the primary variables on well elements
+ arrayView1d< real64 const > const & wellElemPressure =
+ subRegion.getField< fields::well::pressure >();
+ arrayView2d< real64 const, compflow::USD_COMP > const & wellElemGlobalCompDensity =
+ subRegion.getField< fields::well::globalCompDensity >();
+ arrayView1d< real64 const > const & wellElemTemperature =
+ subRegion.getField< fields::well::temperature >();
+
+ arrayView1d< real64 > const & wellElemPressure_n =
+ subRegion.getField< fields::well::pressure_n >();
+ wellElemPressure_n.setValues< parallelDevicePolicy<> >( wellElemPressure );
+
+ if( isThermal() )
+ {
+
+ arrayView1d< real64 > const & wellElemTemperature_n =
+ subRegion.getField< fields::well::temperature_n >();
+ wellElemTemperature_n.setValues< parallelDevicePolicy<> >( wellElemTemperature );
+ }
+
+ arrayView2d< real64, compflow::USD_COMP > const & wellElemGlobalCompDensity_n =
+ subRegion.getField< fields::well::globalCompDensity_n >();
+ wellElemGlobalCompDensity_n.setValues< parallelDevicePolicy<> >( wellElemGlobalCompDensity );
+
+ arrayView1d< real64 const > const & connRate =
+ subRegion.getField< fields::well::mixtureConnectionRate >();
+ arrayView1d< real64 > const & connRate_n =
+ subRegion.getField< fields::well::mixtureConnectionRate_n >();
+ connRate_n.setValues< parallelDevicePolicy<> >( connRate );
+
+ arrayView2d< real64 const, compflow::USD_PHASE > const wellElemPhaseVolFrac =
+ subRegion.getField< fields::well::phaseVolumeFraction >();
+ arrayView2d< real64, compflow::USD_PHASE > const wellElemPhaseVolFrac_n =
+ subRegion.getField< fields::well::phaseVolumeFraction_n >();
+ wellElemPhaseVolFrac_n.setValues< parallelDevicePolicy<> >( wellElemPhaseVolFrac );
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName );
+ fluid.saveConvergedState();
+
- } );
- } );
}
void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n,
@@ -2316,5 +2959,75 @@ void CompositionalMultiphaseWell::printRates( real64 const & time_n,
} );
}
+
+bool CompositionalMultiphaseWell::evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion )
+{
+ WellControls & wellControls = getWellControls( subRegion );
+ // create list of all constraints to process
+ std::vector< WellConstraintBase * > constraintList;
+ if( wellControls.isProducer() )
+ {
+ constraintList = wellControls.getProdRateConstraints();
+ // Solve minimum bhp constraint first
+ constraintList.insert( constraintList.begin(), wellControls.getMinBHPConstraint() );
+ }
+ else
+ {
+ constraintList = wellControls.getInjRateConstraints();
+ // Solve maximum bhp constraint first;
+ constraintList.insert( constraintList.begin(), wellControls.getMaxBHPConstraint() );
+ }
+ // Get current constraint
+ WellConstraintBase * limitingConstraint = nullptr;
+ for( auto & constraint : constraintList )
+ {
+ if( constraint->getName() == wellControls.getCurrentConstraint()->getName())
+ {
+ limitingConstraint = constraint;
+ // tjb. this is likely not needed. set in update state
+ constraint->setBHP ( wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setPhaseVolumeRates ( wellControls.getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) );
+ constraint->setTotalVolumeRate ( wellControls.getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ));
+ constraint->setMassRate( wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() ));
+ GEOS_LOG_RANK_IF ( getLogLevel() > 4 && subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " Limiting Constraint " << limitingConstraint->getName() << " " << limitingConstraint->bottomHolePressure() << " " <<
+ limitingConstraint->phaseVolumeRates() << " " <<
+ limitingConstraint->totalVolumeRate() << " " << limitingConstraint->massRate());
+ }
+ }
+
+
+ // Check current against other constraints
+ for( auto & constraint : constraintList )
+ {
+
+ if( limitingConstraint->getName() != constraint->getName())
+ {
+ if( constraint->checkViolation( *limitingConstraint, time_n ) )
+ {
+ limitingConstraint = constraint;
+ wellControls.setControl( static_cast< WellControls::Control >(constraint->getControl()) ); // tjb old
+ wellControls.setCurrentConstraint( constraint );
+ constraint->setBHP ( wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setPhaseVolumeRates ( wellControls.getReference< array1d< real64 > >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ) );
+ constraint->setTotalVolumeRate ( wellControls.getReference< real64 >(
+ CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() ));
+ constraint->setMassRate( wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() ));
+ GEOS_LOG_RANK_IF ( getLogLevel() > 4 && subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " New Limiting Constraint " << constraint->getName() << " " << constraint->getConstraintValue( time_n ) );
+ }
+ }
+ }
+ GEOS_LOG_RANK_IF ( getLogLevel() > 4 && subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " Limiting Constraint " << limitingConstraint->getName() << " " << limitingConstraint->bottomHolePressure() << " " <<
+ limitingConstraint->phaseVolumeRates() << " " <<
+ limitingConstraint->totalVolumeRate() << " " << limitingConstraint->massRate());
+
+ return true;
+}
REGISTER_CATALOG_ENTRY( PhysicsSolverBase, CompositionalMultiphaseWell, string const &, Group * const )
-} // namespace geos
+} // namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp
index fd874ec5a0e..23b39915b21 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp
@@ -25,6 +25,8 @@
#include "physicsSolvers/fluidFlow/wells/WellSolverBase.hpp"
#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp"
+
namespace geos
{
@@ -92,6 +94,13 @@ class CompositionalMultiphaseWell : public WellSolverBase
/**@{*/
+ virtual real64
+ calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) override;
+
virtual real64
calculateResidualNorm( real64 const & time_n,
real64 const & dt,
@@ -99,17 +108,37 @@ class CompositionalMultiphaseWell : public WellSolverBase
DofManager const & dofManager,
arrayView1d< real64 const > const & localRhs ) override;
+ virtual real64
+ scalingForWellSystemSolution( ElementSubRegionBase & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution ) override;
+
virtual real64
scalingForSystemSolution( DomainPartition & domain,
DofManager const & dofManager,
arrayView1d< real64 const > const & localSolution ) override;
+ virtual bool
+ checkWellSystemSolution( ElementSubRegionBase & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor ) override;
+
virtual bool
checkSystemSolution( DomainPartition & domain,
DofManager const & dofManager,
arrayView1d< real64 const > const & localSolution,
real64 const scalingFactor ) override;
+ virtual void
+ applyWellSystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ WellElementSubRegion & subRegion ) override;
+
virtual void
applySystemSolution( DofManager const & dofManager,
arrayView1d< real64 const > const & localSolution,
@@ -159,6 +188,21 @@ class CompositionalMultiphaseWell : public WellSolverBase
*/
void updateFluidModel( WellElementSubRegion & subRegion );
+ /**
+ * @brief Update well separator using current values of pressure and composition at the reference element
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ * @param targetIndex the targetIndex of the subRegion
+ */
+ void updateSeparator( WellElementSubRegion & subRegion );
+
+ /**
+ * @brief Calculate well rates at reference element
+ * @param subRegion the well subregion containing all the primary and dependent fields
+ * @param targetIndex the targetIndex of the subRegion
+ */
+
+ void calculateReferenceElementRates( WellElementSubRegion & subRegion );
+
/**
* @brief Recompute phase volume fractions (saturations) from constitutive and primary variables
* @param subRegion the well subregion containing all the primary and dependent fields
@@ -172,6 +216,16 @@ class CompositionalMultiphaseWell : public WellSolverBase
*/
void updateTotalMassDensity( WellElementSubRegion & subRegion ) const;
+ /**
+ * @brief Recompute the perforation rates for all the wells
+ * @param domain the domain containing the mesh and fields
+ */
+ virtual void computeWellPerforationRates( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager const & elemManager,
+ WellElementSubRegion & subRegion )override;
+
+
/**
* @brief Recompute the perforation rates for all the wells
* @param domain the domain containing the mesh and fields
@@ -183,6 +237,7 @@ class CompositionalMultiphaseWell : public WellSolverBase
* @brief Recompute all dependent quantities from primary variables (including constitutive models)
* @param subRegion the well subregion containing all the primary and dependent fields
*/
+ virtual real64 updateWellState( WellElementSubRegion & subRegion ) override;
virtual void updateState( DomainPartition & domain ) override;
virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override;
@@ -197,6 +252,13 @@ class CompositionalMultiphaseWell : public WellSolverBase
integer useTotalMassEquation() const { return m_useTotalMassEquation; }
+ virtual void assembleWellFluxTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
/**
* @brief assembles the flux terms for all connections between well elements
* @param time_n previous time value
@@ -213,6 +275,14 @@ class CompositionalMultiphaseWell : public WellSolverBase
DofManager const & dofManager,
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )override;
+
+ virtual void assembleWellAccumulationTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
/**
* @brief assembles the accumulation term for all the well elements
* @param domain the physical domain object
@@ -227,6 +297,21 @@ class CompositionalMultiphaseWell : public WellSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) override;
+ virtual void assembleWellConstraintTerms( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+
+ virtual void assembleWellPressureRelations( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
/**
* @brief assembles the pressure relations at all connections between well elements except at the well head
* @param time_n time at the beginning of the time step
@@ -249,6 +334,15 @@ class CompositionalMultiphaseWell : public WellSolverBase
*/
void chopNegativeDensities( DomainPartition & domain );
+ void chopNegativeDensities( WellElementSubRegion & subRegion );
+
+ /**
+ * @brief Initialize all the primary and secondary variables in all the wells
+ * @param domain the domain containing the well manager to access individual wells
+ */
+ void initializeWells( DomainPartition & domain, real64 const & time_n ) override;
+ void initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n ) override;
+
struct viewKeyStruct : WellSolverBase::viewKeyStruct
{
static constexpr char const * dofFieldString() { return "compositionalWellVars"; }
@@ -276,32 +370,13 @@ class CompositionalMultiphaseWell : public WellSolverBase
static constexpr char const * massDensityString() { return "massDensity";}
static constexpr char const * currentBHPString() { return "currentBHP"; }
- static constexpr char const * dCurrentBHPString() { return "dCurrentBHP"; }
-
- static constexpr char const * dCurrentBHP_dPresString() { return "dCurrentBHP_dPres"; }
- static constexpr char const * dCurrentBHP_dCompDensString() { return "dCurrentBHP_dCompDens"; }
static constexpr char const * currentPhaseVolRateString() { return "currentPhaseVolumetricRate"; }
- static constexpr char const * dCurrentPhaseVolRateString() { return "dCurrentPhaseVolumetricRate"; }
-
-
- static constexpr char const * dCurrentPhaseVolRate_dPresString() { return "dCurrentPhaseVolumetricRate_dPres"; }
-
- static constexpr char const * dCurrentPhaseVolRate_dCompDensString() { return "dCurrentPhaseVolumetricRate_dCompDens"; }
-
- static constexpr char const * dCurrentPhaseVolRate_dRateString() { return "dCurrentPhaseVolumetricRate_dRate"; }
static constexpr char const * currentTotalVolRateString() { return "currentTotalVolumetricRate"; }
- static constexpr char const * dCurrentTotalVolRateString() { return "dCurrentTotalVolumetricRate"; }
static constexpr char const * currentMassRateString() { return "currentMassRate"; }
- static constexpr char const * dCurrentTotalVolRate_dPresString() { return "dCurrentTotalVolumetricRate_dPres"; }
-
- static constexpr char const * dCurrentTotalVolRate_dCompDensString() { return "dCurrentTotalVolumetricRate_dCompDens"; }
-
- static constexpr char const * dCurrentTotalVolRate_dRateString() { return "dCurrentTotalVolumetricRate_dRate"; }
-
} viewKeysCompMultiphaseWell;
protected:
@@ -312,6 +387,7 @@ class CompositionalMultiphaseWell : public WellSolverBase
virtual void initializePostInitialConditionsPreSubGroups() override;
+ void saveState( WellElementSubRegion & subRegion );
virtual void postRestartInitialization() override final;
/*
* @brief Utility function that checks the consistency of the constitutive models
@@ -330,11 +406,6 @@ class CompositionalMultiphaseWell : public WellSolverBase
void validateWellControlsForFluid( WellControls const & wellControls,
constitutive::MultiFluidBase const & fluid ) const;
- /**
- * @brief Checks injection streams for validity (compositions sum to one)
- * @param subRegion the well subRegion
- */
- void validateInjectionStreams( WellElementSubRegion const & subRegion ) const;
/**
* @brief Make sure that the well constraints are compatible
@@ -357,16 +428,26 @@ class CompositionalMultiphaseWell : public WellSolverBase
real64 const & dt,
DomainPartition & domain ) override;
-private:
+ virtual bool evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion ) override;
- /**
- * @brief Initialize all the primary and secondary variables in all the wells
- * @param domain the domain containing the well manager to access individual wells
- */
- void initializeWells( DomainPartition & domain, real64 const & time_n ) override;
+private:
virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override;
+ template< typename ... GROUPTYPES >
+ void selectLimitingConstraint( real64 const & time_n, integer const coupledIterationNumber, WellElementSubRegion & subRegion );
+
+ void solveConstraint( std::shared_ptr< WellConstraintBase > constraint,
+ real64 const & time_n,
+ real64 const & dt,
+ integer const cycleNumber,
+ integer const coupledIterationNumber,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion,
+ DofManager const & dofManager );
/// flag indicating whether mass or molar formulation should be used
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp
index ce588ad3d5c..9463eb335bc 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp
@@ -44,7 +44,7 @@
#include "physicsSolvers/fluidFlow/kernels/singlePhase/FluidUpdateKernel.hpp"
#include "physicsSolvers/fluidFlow/kernels/singlePhase/SolutionCheckKernel.hpp"
#include "physicsSolvers/fluidFlow/SinglePhaseStatistics.hpp"
-
+#include "physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellConstraintKernels.hpp"
namespace geos
{
@@ -143,6 +143,7 @@ void SinglePhaseWell::validateWellConstraints( real64 const & time_n,
WellElementSubRegion const & subRegion,
ElementRegionManager const & elemManager )
{
+ GEOS_UNUSED_VAR( time_n ); // tjb this will be needed with validation against tables
WellControls & wellControls = getWellControls( subRegion );
if( !wellControls.useSurfaceConditions() )
{
@@ -176,7 +177,9 @@ void SinglePhaseWell::validateWellConstraints( real64 const & time_n,
wellControls.setRegionAverageTemperature( stats.averageTemperature );
}
}
+ #if 0 // tjb vix this
WellControls::Control currentControl = wellControls.getControl();
+
real64 const targetTotalRate = wellControls.getTargetTotalRate( time_n );
real64 const targetPhaseRate = wellControls.getTargetPhaseRate( time_n );
GEOS_THROW_IF( currentControl == WellControls::Control::PHASEVOLRATE,
@@ -192,7 +195,38 @@ void SinglePhaseWell::validateWellConstraints( real64 const & time_n,
GEOS_THROW_IF( !isZero( targetPhaseRate ),
"WellControls " << wellControls.getDataContext() <<
": Target phase rate cannot be used for SinglePhaseWell",
- InputError, wellControls.getDataContext() );
+ InputError );
+#endif
+}
+
+void SinglePhaseWell::initializePostInitialConditionsPreSubGroups()
+{
+ WellSolverBase::initializePostInitialConditionsPreSubGroups();
+ createSeparator();
+}
+void SinglePhaseWell::createSeparator()
+{
+ DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" );
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+
+ // loop over the wells
+ mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+ // setup fluid separator
+ WellControls & wellControls = getWellControls( subRegion );
+ string const fluidSeparatorName = wellControls.getName() + "Separator";
+ std::unique_ptr< constitutive::ConstitutiveBase > fluidSeparatorPtr = fluid.deliverClone( fluidSeparatorName, &wellControls );
+ fluidSeparatorPtr->allocateConstitutiveData( wellControls, 1 );
+ fluidSeparatorPtr->resize( 1 );
+ wellControls.setFluidSeparator( std::move( fluidSeparatorPtr ));
+ } );
+ } );
}
void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion )
@@ -262,7 +296,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion )
}
-void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegion )
+void SinglePhaseWell::calculateReferenceElementRates( WellElementSubRegion & subRegion )
{
GEOS_MARK_FUNCTION;
@@ -276,9 +310,6 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi
// subRegion data
- arrayView1d< real64 const > const pres =
- subRegion.getField< well::pressure >();
-
arrayView1d< real64 const > const & connRate =
subRegion.getField< well::connectionRate >();
@@ -287,14 +318,71 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi
string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & dens = fluid.density();
- arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const & dDens = fluid.dDensity();
+
// control data
+ WellControls & wellControls = getWellControls( subRegion );
+
+ real64 & currentVolRate =
+ wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() );
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [connRate,
+ dens,
+ ¤tVolRate,
+ &iwelemRef] ( localIndex const )
+ {
+ real64 const densInv = 1.0 / dens[iwelemRef][0];
+ currentVolRate = connRate[iwelemRef] * densInv;
+ // tjb compute mass
+ } );
+
+
+}
+
+void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const
+{
+ GEOS_MARK_FUNCTION;
+
+ arrayView1d< real64 const > const pres = subRegion.getField< well::pressure >();
+ arrayView1d< real64 const > const temp = subRegion.getField< well::temperature >();
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+
+ constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ {
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+ singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp );
+ } );
+}
+void SinglePhaseWell::updateSeparator( WellElementSubRegion & subRegion )
+{
+ GEOS_MARK_FUNCTION;
+
+ // the rank that owns the reference well element is responsible for the calculations below.
+ if( !subRegion.isLocallyOwned() )
+ {
+ return;
+ }
+
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+
+ // subRegion data
+ arrayView1d< real64 const > const pres =
+ subRegion.getField< well::pressure >();
+
+ // control data
WellControls & wellControls = getWellControls( subRegion );
string const wellControlsName = wellControls.getName();
bool const logSurfaceCondition = isLogLevelActive< logInfo::WellControl >( wellControls.getLogLevel());
integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+
+ // fluid data
+ constitutive::SingleFluidBase & fluidSeparator = wellControls.getSingleFluidSeparator();
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & dens = fluidSeparator.density();
+
real64 flashPressure;
if( useSurfaceConditions )
{
@@ -311,31 +399,22 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi
flashPressure = pres[iwelemRef];
}
}
- real64 & currentVolRate =
- wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() );
- arrayView1d< real64 > const & dCurrentVolRate =
- wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentVolRateString() );
-
- constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
+ constitutiveUpdatePassThru( fluidSeparator, [&]( auto & castedFluid )
{
- typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
+ typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidSeparatorWrapper = castedFluid.createKernelWrapper();
geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL )
{
integer constexpr IS_THERMAL = ISTHERMAL();
- using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >;
+ GEOS_UNUSED_VAR( IS_THERMAL );
// bring everything back to host, capture the scalars by reference
- forAll< serialPolicy >( 1, [fluidWrapper,
+ forAll< serialPolicy >( 1, [fluidSeparatorWrapper,
pres,
- connRate,
dens,
- dDens,
logSurfaceCondition,
&useSurfaceConditions,
&flashPressure,
- ¤tVolRate,
- dCurrentVolRate,
&iwelemRef,
&wellControlsName] ( localIndex const )
{
@@ -346,7 +425,7 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi
if( useSurfaceConditions )
{
// we need to compute the surface density
- fluidWrapper.update( iwelemRef, 0, flashPressure );
+ fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure );
if( logSurfaceCondition )
{
@@ -361,62 +440,204 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi
}
else
{
- real64 const refPres = pres[iwelemRef];
- fluidWrapper.update( iwelemRef, 0, refPres );
- }
-
- real64 const densInv = 1.0 / dens[iwelemRef][0];
- currentVolRate = connRate[iwelemRef] * densInv;
-
- dCurrentVolRate[COFFSET_WJ::dP] = -( useSurfaceConditions == 0 ) * dDens[iwelemRef][0][DerivOffset::dP] * currentVolRate * densInv;
- dCurrentVolRate[COFFSET_WJ::dQ] = densInv;
- if constexpr ( IS_THERMAL )
- {
- dCurrentVolRate[COFFSET_WJ::dT] = -( useSurfaceConditions == 0 ) * dDens[iwelemRef][0][DerivOffset::dT] * currentVolRate * densInv;
- }
- if( logSurfaceCondition && useSurfaceConditions )
- {
- GEOS_LOG_RANK( GEOS_FMT( "{}: total fluid density at surface conditions = {} kg/sm3, total rate = {} kg/s, total surface volumetric rate = {} sm3/s",
- wellControlsName, dens[iwelemRef][0], connRate[iwelemRef], currentVolRate ) );
+ fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure );
}
} );
} );
} );
}
-void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const
+real64 SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion )
{
- GEOS_MARK_FUNCTION;
+ WellControls & wellControls = getWellControls( subRegion );
+ if( wellControls.getWellState())
+ {
+ if( m_useNewCode )
+ {
+ // update volumetric rates for the well constraints
+ // Warning! This must be called before updating the fluid model
+ //calculateReferenceElementRates( subRegion );
+
+ // update density in the well elements
+ updateFluidModel( subRegion );
+ updateSeparator( subRegion ); // Calculate fluid properties at control conditions
+
+ // Calculate the reference element rates
+ calculateReferenceElementRates( subRegion );
+ // update the current BHP
+ updateBHPForConstraint( subRegion );
+ }
+ else
+ {
+ // update volumetric rates for the well constraints
+ // Warning! This must be called before updating the fluid model
+ calculateReferenceElementRates( subRegion );
- arrayView1d< real64 const > const pres = subRegion.getField< well::pressure >();
- arrayView1d< real64 const > const temp = subRegion.getField< well::temperature >();
+ // update density in the well elements
+ updateFluidModel( subRegion );
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+ // update the current BHP
+ updateBHPForConstraint( subRegion );
+ }
- constitutiveUpdatePassThru( fluid, [&]( auto & castedFluid )
- {
- typename TYPEOFREF( castedFluid ) ::KernelWrapper fluidWrapper = castedFluid.createKernelWrapper();
- singlePhaseBaseKernels::FluidUpdateKernel::launch( fluidWrapper, pres, temp );
- } );
+ }
+ return 0.0; // change in phasevolume fraction doesnt apply
}
-
-real64 SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion )
+void SinglePhaseWell::initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n )
{
- // update volumetric rates for the well constraints
- // Warning! This must be called before updating the fluid model
- updateVolRateForConstraint( subRegion );
+ GEOS_UNUSED_VAR( domain );
+ WellControls & wellControls = getWellControls( subRegion );
+ PerforationData const & perforationData = *subRegion.getPerforationData();
- // update density in the well elements
- updateFluidModel( subRegion );
+ // get the info stored on well elements
+ arrayView1d< real64 const > const wellElemGravCoef =
+ subRegion.getField< well::gravityCoefficient >();
- // update the current BHP
- updateBHPForConstraint( subRegion );
+ // get well primary variables on well elements
+ arrayView1d< real64 > const wellElemPressure =
+ subRegion.getField< well::pressure >();
+ arrayView1d< real64 > const connRate =
+ subRegion.getField< well::connectionRate >();
+ arrayView1d< real64 > const wellElemTemperature =
+ subRegion.getField< well::temperature >();
+ // get the element region, subregion, index
+ arrayView1d< localIndex const > const resElementRegion =
+ perforationData.getField< perforation::reservoirElementRegion >();
+ arrayView1d< localIndex const > const resElementSubRegion =
+ perforationData.getField< perforation::reservoirElementSubRegion >();
+ arrayView1d< localIndex const > const resElementIndex =
+ perforationData.getField< perforation::reservoirElementIndex >();
+
+ arrayView1d< real64 const > const & perfGravCoef =
+ perforationData.getField< well::gravityCoefficient >();
+
+ bool const hasNonZeroRate = MpiWrapper::max< integer >( hasNonZero( connRate ));
+
+ if( time_n <= 0.0 || (wellControls.isWellOpen() && !hasNonZeroRate ) )
+ {
+ wellControls.setWellState( true );
+ if( wellControls.getCurrentConstraint() == nullptr )
+ {
+ if( wellControls.isProducer() )
+ {
+ wellControls.forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( ConstraintTypeId( wellControls.getControl()) == constraint.getControl() )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ wellControls.setControl( static_cast< WellControls::Control >(constraint.getControl()) ); // tjb old
+ }
+ } );
+ }
+ else
+ {
+ wellControls.forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >,
+ InjectionConstraint< PhaseVolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( ConstraintTypeId( wellControls.getControl()) == constraint.getControl() )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ wellControls.setControl( static_cast< WellControls::Control >(constraint.getControl()) ); // tjb old
+ }
+ } );
+ }
+ }
- // note: the perforation rates are updated separately
- return 0.0; // change in phasevolume fraction doesnt apply
-}
+ // TODO: change the way we access the flowSolver here
+ SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() );
+ PresTempInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( mesh.getElemManager(), flowSolver.getName() );
+ PresTempInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( mesh.getElemManager(), flowSolver.getName() );
+
+ // 1) Loop over all perforations to compute an average density
+ // 2) Initialize the reference pressure
+ // 3) Estimate the pressures in the well elements using the average density
+ PresTempInitializationKernel::
+ launch( isThermal(),
+ perforationData.size(),
+ subRegion.size(),
+ perforationData.getNumPerforationsGlobal(),
+ wellControls,
+ 0.0, // initialization done at t = 0
+ resSinglePhaseFlowAccessors.get( flow::pressure{} ),
+ resSinglePhaseFlowAccessors.get( flow::temperature{} ),
+ resSingleFluidAccessors.get( fields::singlefluid::density{} ),
+ resElementRegion,
+ resElementSubRegion,
+ resElementIndex,
+ perfGravCoef,
+ wellElemGravCoef,
+ wellElemPressure,
+ wellElemTemperature );
+
+ // 4) Recompute the pressure-dependent properties
+ // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState)
+ // to better initialize the rates
+ updateSubRegionState( subRegion );
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & wellElemDens = fluid.density();
+
+ // 5) Estimate the well rates
+ RateInitializationKernel::launch( subRegion.size(),
+ wellControls,
+ 0.0, // initialization done at t = 0
+ wellElemDens,
+ connRate );
+
+ calculateReferenceElementRates( subRegion );
+ WellConstraintBase * constraint = wellControls.getCurrentConstraint();
+ constraint->setBHP ( wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setTotalVolumeRate ( wellControls.getReference< real64 >(
+ SinglePhaseWell::viewKeyStruct::currentVolRateString() ));
+ //constraint->setMassRate( wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentMassRateString() ));
+ // 7) Copy well / fluid dofs to "prop"_n variables
+ saveState( subRegion );
+ }
+ else if( !hasNonZeroRate )
+ {
+ wellControls.setWellState( false );
+ GEOS_LOG_RANK_0( "tjb shut wells "<< subRegion.getName());
+ }
+ else
+ {
+ wellControls.setWellState( true );
+ // setup for restart
+ if( wellControls.getCurrentConstraint() == nullptr )
+ {
+ updateSubRegionState( subRegion );
+ if( wellControls.isProducer() )
+ {
+ wellControls.forSubGroups< MinimumBHPConstraint, ProductionConstraint< VolumeRateConstraint >, ProductionConstraint< MassRateConstraint >,
+ ProductionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ & constraint )
+ {
+ if( ConstraintTypeId( wellControls.getControl()) == constraint.getControl() )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ }
+ } );
+ }
+ else
+ {
+ wellControls.forSubGroups< MaximumBHPConstraint, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint >, InjectionConstraint< PhaseVolumeRateConstraint > >( [&](
+ auto
+ &
+ constraint )
+ {
+ if( ConstraintTypeId( wellControls.getControl()) == constraint.getControl() )
+ {
+ wellControls.setCurrentConstraint( &constraint );
+ }
+ } );
+ }
+ }
+ }
+
+}
void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & time_n )
{
GEOS_MARK_FUNCTION;
@@ -424,87 +645,16 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const &
// loop over the wells
forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel & meshLevel,
+ MeshLevel & mesh,
string_array const & regionNames )
{
- ElementRegionManager & elemManager = meshLevel.getElemManager();
+ ElementRegionManager & elemManager = mesh.getElemManager();
elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
[&]( localIndex const,
WellElementSubRegion & subRegion )
{
- WellControls const & wellControls = getWellControls( subRegion );
- PerforationData const & perforationData = *subRegion.getPerforationData();
-
- // get the info stored on well elements
- arrayView1d< real64 const > const wellElemGravCoef =
- subRegion.getField< well::gravityCoefficient >();
-
- // get well primary variables on well elements
- arrayView1d< real64 > const wellElemPressure =
- subRegion.getField< well::pressure >();
- arrayView1d< real64 > const connRate =
- subRegion.getField< well::connectionRate >();
- arrayView1d< real64 > const wellElemTemperature =
- subRegion.getField< well::temperature >();
- // get the element region, subregion, index
- arrayView1d< localIndex const > const resElementRegion =
- perforationData.getField< perforation::reservoirElementRegion >();
- arrayView1d< localIndex const > const resElementSubRegion =
- perforationData.getField< perforation::reservoirElementSubRegion >();
- arrayView1d< localIndex const > const resElementIndex =
- perforationData.getField< perforation::reservoirElementIndex >();
-
- arrayView1d< real64 const > const & perfGravCoef =
- perforationData.getField< well::gravityCoefficient >();
-
- bool const hasNonZeroRate = MpiWrapper::max< integer >( hasNonZero( connRate ));
-
- if( wellControls.isWellOpen() && !hasNonZeroRate )
- {
- // TODO: change the way we access the flowSolver here
- SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() );
- PresTempInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( meshLevel.getElemManager(), flowSolver.getName() );
- PresTempInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( meshLevel.getElemManager(), flowSolver.getName() );
-
- // 1) Loop over all perforations to compute an average density
- // 2) Initialize the reference pressure
- // 3) Estimate the pressures in the well elements using the average density
- PresTempInitializationKernel::
- launch( isThermal(),
- perforationData.size(),
- subRegion.size(),
- perforationData.getNumPerforationsGlobal(),
- wellControls,
- 0.0, // initialization done at t = 0
- resSinglePhaseFlowAccessors.get( flow::pressure{} ),
- resSinglePhaseFlowAccessors.get( flow::temperature{} ),
- resSingleFluidAccessors.get( fields::singlefluid::density{} ),
- resElementRegion,
- resElementSubRegion,
- resElementIndex,
- perfGravCoef,
- wellElemGravCoef,
- wellElemPressure,
- wellElemTemperature );
-
- // 4) Recompute the pressure-dependent properties
- // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState)
- // to better initialize the rates
- updateSubRegionState( subRegion );
-
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
- arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & wellElemDens = fluid.density();
-
- // 5) Estimate the well rates
- RateInitializationKernel::launch( subRegion.size(),
- wellControls,
- 0.0, // initialization done at t = 0
- wellElemDens,
- connRate );
- }
-
+ initializeWell( domain, mesh, subRegion, time_n );
} );
} );
@@ -585,6 +735,33 @@ void SinglePhaseWell::shutDownWell( real64 const time_n,
} );
}
+real64 SinglePhaseWell::updateWellState( WellElementSubRegion & subRegion )
+{
+ GEOS_MARK_FUNCTION;
+
+ updateSubRegionState( subRegion );
+ return 0.0;
+}
+void SinglePhaseWell::updateState( DomainPartition & domain )
+{
+ GEOS_MARK_FUNCTION;
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
+ WellElementSubRegion & subRegion )
+ {
+ WellControls & wellControls = getWellControls( subRegion );
+ if( wellControls.getWellState())
+ {
+ updateWellState( subRegion );
+ }
+ } );
+ } );
+
+}
void SinglePhaseWell::assembleSystem( real64 const time,
real64 const dt,
DomainPartition & domain,
@@ -594,11 +771,40 @@ void SinglePhaseWell::assembleSystem( real64 const time,
{
string const wellDofKey = dofManager.getKey( wellElementDofName());
+ if( m_useNewCode )
+ {
+ // selects constraints one of 2 ways
+ // wellEstimator flag set to 0 => orginal logic rates are computed during update state and constraints are selected every newton
+ // iteration
+ // wellEstimator flag > 0 => well esitmator solved for each constraint and then selects the constraint
+ // => estimator solve only performed first "wellEstimator" iterations
+ NonlinearSolverParameters const & nonlinearParams = getNonlinearSolverParameters();
+ selectWellConstraint( time, dt, nonlinearParams.m_numNewtonIterations, domain );
+ }
+
// assemble the accumulation term in the mass balance equations
assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs );
// then assemble the pressure relations between well elements
assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs );
+ {
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ ElementRegionManager & elementRegionManager = mesh.getElemManager();
+ elementRegionManager.forElementRegions< WellElementRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementRegion & region )
+ {
+ WellElementSubRegion & subRegion = region.getGroup( ElementRegionBase::viewKeyStruct::elementSubRegions() )
+ .getGroup< WellElementSubRegion >( region.getSubRegionName() );
+ WellControls & wellControls = getWellControls( subRegion );
+ if( !wellControls.getConstraintSwitch() )
+ assembleWellConstraintTerms( time, dt, subRegion, dofManager, localMatrix.toViewConstSizes(), localRhs );
+ } );
+ } );
+ }
// then compute the perforation rates (later assembled by the coupled solver)
computePerforationRates( time, dt, domain );
@@ -611,6 +817,48 @@ void SinglePhaseWell::assembleSystem( real64 const time,
shutDownWell( time, domain, dofManager, localMatrix, localRhs );
}
+void SinglePhaseWell::assembleWellFluxTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+ GEOS_UNUSED_VAR( time );
+ WellControls const & wellControls = getWellControls( subRegion );
+ // get a reference to the degree-of-freedom numbers
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+ if( isThermal() )
+ {
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+ thermalSinglePhaseWellKernels::
+ FaceBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( dt,
+ dofManager.rankOffset(),
+ wellDofKey,
+ wellControls,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ singlePhaseWellKernels::
+ FaceBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( dt,
+ dofManager.rankOffset(),
+ wellDofKey,
+ wellControls,
+ subRegion,
+ localMatrix,
+ localRhs );
+ }
+
+}
void SinglePhaseWell::assembleFluxTerms( real64 const & time_n,
real64 const & dt,
DomainPartition & domain,
@@ -619,8 +867,6 @@ void SinglePhaseWell::assembleFluxTerms( real64 const & time_n,
arrayView1d< real64 > const & localRhs )
{
GEOS_MARK_FUNCTION;
- GEOS_UNUSED_VAR( time_n );
- GEOS_UNUSED_VAR( dt );
// loop over the wells
forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
@@ -635,45 +881,106 @@ void SinglePhaseWell::assembleFluxTerms( real64 const & time_n,
WellElementSubRegion const & subRegion )
{
- WellControls const & wellControls = getWellControls( subRegion );
- // get a reference to the degree-of-freedom numbers
- string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ assembleWellFluxTerms( time_n, dt, subRegion, dofManager, localMatrix, localRhs );
+ } );
- if( isThermal() )
- {
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
- thermalSinglePhaseWellKernels::
- FaceBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( dt,
- dofManager.rankOffset(),
- wellDofKey,
- wellControls,
- subRegion,
- fluid,
- localMatrix,
- localRhs );
- }
- else
+ } );
+}
+
+
+void SinglePhaseWell::assembleWellConstraintTerms( real64 const & time_n,
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+
+
+ // the rank that owns the reference well element is responsible for the calculations below.
+ if( !subRegion.isLocallyOwned() )
+ {
+ return;
+ }
+ WellControls & wellControls = getWellControls( subRegion );
+
+ {
+ // tjb wellControls.forSubGroups< BHPConstraint, MassConstraint, VolumeRateConstraint >( [&]( auto & constraint )
+ wellControls.forSubGroups< BHPConstraint, InjectionConstraint< VolumeRateConstraint >, ProductionConstraint< VolumeRateConstraint > >( [&]( auto & constraint )
+ {
+ if( constraint.getName() == wellControls.getCurrentConstraint()->getName())
{
- singlePhaseWellKernels::
- FaceBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( dt,
- dofManager.rankOffset(),
- wellDofKey,
- wellControls,
- subRegion,
- localMatrix,
- localRhs );
+ // found limiting constraint
+
+ // fluid data
+ constitutive::SingleFluidBase & fluidSeparator = wellControls.getSingleFluidSeparator();
+ integer isThermal = fluidSeparator.isThermal();
+
+ geos::internal::kernelLaunchSelectorThermalSwitch( isThermal, [&] ( auto ISTHERMAL )
+ {
+ integer constexpr IS_THERMAL = ISTHERMAL();
+
+ singlePhaseWellConstraintKernels::ConstraintHelper< IS_THERMAL >::assembleConstraintEquation( time_n,
+ wellControls,
+ constraint,
+ subRegion,
+ dofManager.getKey( wellElementDofName() ),
+ dofManager.rankOffset(),
+ localMatrix,
+ localRhs );
+ } );
}
} );
+ }
- } );
}
+void SinglePhaseWell::assembleWellPressureRelations( real64 const & GEOS_UNUSED_PARAM( time_n ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+{
+
+ // get the degrees of freedom numbers, depth, next well elem index
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ arrayView1d< globalIndex const > const & wellElemDofNumber =
+ subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & wellElemGravCoef =
+ subRegion.getField< well::gravityCoefficient >();
+ arrayView1d< localIndex const > const & nextWellElemIndex =
+ subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() );
+
+ // get primary variables on well elements
+ arrayView1d< real64 const > const & wellElemPressure =
+ subRegion.getField< well::pressure >();
+
+ // get well constitutive data
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & wellElemDensity = fluid.density();
+ arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const & dWellElemDensity = fluid.dDensity();
+
+ geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL )
+ {
+ PressureRelationKernel::launch< ISTHERMAL >( subRegion.size(),
+ dofManager.rankOffset(),
+ wellElemDofNumber,
+ wellElemGravCoef,
+ nextWellElemIndex,
+ wellElemPressure,
+ wellElemDensity,
+ dWellElemDensity,
+ localMatrix,
+ localRhs );
+ } );
+
+}
void SinglePhaseWell::assemblePressureRelations( real64 const & time_n,
- real64 const & GEOS_UNUSED_PARAM( dt ),
+ real64 const & dt,
DomainPartition const & domain,
DofManager const & dofManager,
CRSMatrixView< real64, globalIndex const > const & localMatrix,
@@ -694,68 +1001,53 @@ void SinglePhaseWell::assemblePressureRelations( real64 const & time_n,
WellElementSubRegion const & subRegion )
{
- WellControls & wellControls = getWellControls( subRegion );
-
- // get the degrees of freedom numbers, depth, next well elem index
- string const wellDofKey = dofManager.getKey( wellElementDofName() );
- arrayView1d< globalIndex const > const & wellElemDofNumber =
- subRegion.getReference< array1d< globalIndex > >( wellDofKey );
- arrayView1d< real64 const > const & wellElemGravCoef =
- subRegion.getField< well::gravityCoefficient >();
- arrayView1d< localIndex const > const & nextWellElemIndex =
- subRegion.getReference< array1d< localIndex > >( WellElementSubRegion::viewKeyStruct::nextWellElementIndexString() );
+ assembleWellPressureRelations( time_n, dt, subRegion, dofManager, localMatrix, localRhs );
+ } );
+ } );
+}
+void SinglePhaseWell::assembleWellAccumulationTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
- // get primary variables on well elements
- arrayView1d< real64 const > const & wellElemPressure =
- subRegion.getField< well::pressure >();
+{
+ GEOS_UNUSED_VAR( time );
+ GEOS_UNUSED_VAR( dt );
+ // get a reference to the degree-of-freedom numbers
+ string const wellElemDofKey = dofManager.getKey( wellElementDofName() );
- // get well constitutive data
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
- arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & wellElemDensity = fluid.density();
- arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const & dWellElemDensity = fluid.dDensity();
+ WellControls const & wellControls = getWellControls( subRegion );
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
- geos::internal::kernelLaunchSelectorThermalSwitch( isThermal(), [&] ( auto ISTHERMAL )
- {
- localIndex controlHasSwitched=0;
- controlHasSwitched = PressureRelationKernel::launch< ISTHERMAL >( subRegion.size(),
- dofManager.rankOffset(),
- subRegion.isLocallyOwned(),
- subRegion.getTopWellElementIndex(),
- wellControls,
- time_n,
- wellElemDofNumber,
- wellElemGravCoef,
- nextWellElemIndex,
- wellElemPressure,
- wellElemDensity,
- dWellElemDensity,
- localMatrix,
- localRhs );
-
- if( controlHasSwitched == 1 )
- {
- // Note: if BHP control is not viable, we switch to TOTALVOLRATE
- // if TOTALVOLRATE is not viable, we switch to BHP
+ if( isThermal() )
+ {
+ thermalSinglePhaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( wellControls.isProducer(),
+ dofManager.rankOffset(),
+ wellElemDofKey,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+ else
+ {
+ singlePhaseWellKernels::
+ ElementBasedAssemblyKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(),
+ wellElemDofKey,
+ subRegion,
+ fluid,
+ localMatrix,
+ localRhs );
+ }
+}
- if( wellControls.getControl() == WellControls::Control::BHP )
- {
- wellControls.switchToTotalRateControl( wellControls.getTargetTotalRate( time_n ) );
- GEOS_LOG_LEVEL_RANK_0( logInfo::WellControl,
- GEOS_FMT( "Control switch for well {} from BHP constraint to rate constraint", subRegion.getName()) );
- }
- else
- {
- wellControls.switchToBHPControl( wellControls.getTargetBHP( time_n ) );
- GEOS_LOG_LEVEL_RANK_0( logInfo::WellControl,
- GEOS_FMT( "Control switch for well {} from rate constraint to BHP constraint", subRegion.getName()) );
- }
- }
- } );
- } );
- } );
-}
void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n,
real64 const & dt,
@@ -765,54 +1057,22 @@ void SinglePhaseWell::assembleAccumulationTerms( real64 const & time_n,
arrayView1d< real64 > const & localRhs )
{
GEOS_MARK_FUNCTION;
- GEOS_UNUSED_VAR( time_n );
- GEOS_UNUSED_VAR( dt );
+
forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
- MeshLevel const & mesh,
+ MeshLevel & mesh,
string_array const & regionNames )
{
- ElementRegionManager const & elemManager = mesh.getElemManager();
+ ElementRegionManager & elemManager = mesh.getElemManager();
elemManager.forElementSubRegions< WellElementSubRegion >( regionNames,
[&]( localIndex const,
- WellElementSubRegion const & subRegion )
+ WellElementSubRegion & subRegion )
{
-
- // get a reference to the degree-of-freedom numbers
- string const wellElemDofKey = dofManager.getKey( wellElementDofName() );
-
- WellControls const & wellControls = getWellControls( subRegion );
- string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
- SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
-
- if( isThermal() )
- {
- thermalSinglePhaseWellKernels::
- ElementBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( wellControls.isProducer(),
- dofManager.rankOffset(),
- wellElemDofKey,
- subRegion,
- fluid,
- localMatrix,
- localRhs );
- }
- else
- {
- singlePhaseWellKernels::
- ElementBasedAssemblyKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( dofManager.rankOffset(),
- wellElemDofKey,
- subRegion,
- fluid,
- localMatrix,
- localRhs );
- }
+ assembleWellAccumulationTerms( time_n, dt, subRegion, dofManager, localMatrix, localRhs );
} );
} );
- // then assemble the volume balance equations
- assembleVolumeBalanceTerms( domain, dofManager, localMatrix, localRhs );
+
}
void SinglePhaseWell::assembleVolumeBalanceTerms( DomainPartition const & GEOS_UNUSED_PARAM( domain ),
@@ -887,6 +1147,123 @@ void SinglePhaseWell::computePerforationRates( real64 const & time_n,
}
+real64
+SinglePhaseWell::calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs )
+{
+ GEOS_MARK_FUNCTION;
+ integer numNorm = 1; // mass balance
+ array1d< real64 > localResidualNorm;
+ array1d< real64 > localResidualNormalizer;
+
+ if( isThermal() )
+ {
+ numNorm = 2; // mass balance and energy balance
+ }
+ localResidualNorm.resize( numNorm );
+ localResidualNormalizer.resize( numNorm );
+
+
+ globalIndex const rankOffset = dofManager.rankOffset();
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+
+
+
+ string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() );
+ SingleFluidBase const & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName );
+
+ WellControls const & wellControls = getWellControls( subRegion );
+
+ // step 1: compute the norm in the subRegion
+ if( isThermal() )
+ {
+ real64 subRegionResidualNorm[2]{};
+ thermalSinglePhaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ for( integer i=0; i localResidualNorm[i] )
+ {
+ localResidualNorm[i] = subRegionResidualNorm[i];
+ }
+ }
+ }
+ else
+ {
+ real64 subRegionResidualNorm[1]{};
+ ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ if( subRegionResidualNorm[0] > localResidualNorm[0] )
+ {
+ localResidualNorm[0] = subRegionResidualNorm[0];
+ }
+ }
+
+
+ real64 resNorm=localResidualNorm[0];
+ if( isThermal() )
+ {
+ real64 globalResidualNorm[2]{};
+ globalResidualNorm[0] = MpiWrapper::max( localResidualNorm[0] );
+ globalResidualNorm[1] = MpiWrapper::max( localResidualNorm[1] );
+ resNorm= std::sqrt( globalResidualNorm[0] * globalResidualNorm[0] + globalResidualNorm[1] * globalResidualNorm[1] );
+
+ GEOS_LOG_LEVEL_RANK_0_NLR( logInfo::ResidualNorm, GEOS_FMT( " ( R{} ) = ( {:4.2e} ) ( Renergy ) = ( {:4.2e} )",
+ coupledSolverAttributePrefix(), globalResidualNorm[0], globalResidualNorm[1] ));
+
+ getConvergenceStats().setResidualValue( GEOS_FMT( "R{}", coupledSolverAttributePrefix()), globalResidualNorm[0] );
+ getConvergenceStats().setResidualValue( "Renergy", globalResidualNorm[1] );
+ }
+ else
+ {
+ resNorm = MpiWrapper::max( resNorm );
+
+ GEOS_LOG_LEVEL_RANK_0_NLR( logInfo::ResidualNorm, GEOS_FMT( " ( R{} ) = ( {:4.2e} )",
+ coupledSolverAttributePrefix(), resNorm ));
+ getConvergenceStats().setResidualValue( GEOS_FMT( "R{}", coupledSolverAttributePrefix()), resNorm );
+ }
+
+ return resNorm;
+}
+real64
+SinglePhaseWell::scalingForWellSystemSolution( ElementSubRegionBase & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution )
+{
+ GEOS_MARK_FUNCTION;
+ GEOS_UNUSED_VAR( subRegion );
+ GEOS_UNUSED_VAR( dofManager );
+ GEOS_UNUSED_VAR( localSolution );
+
+ return 1.0;
+}
+
real64
SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
real64 const & dt,
@@ -895,13 +1272,13 @@ SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
arrayView1d< real64 const > const & localRhs )
{
GEOS_MARK_FUNCTION;
- integer numNorm = 1; // mass balance
+ integer numNorm = 1; // mass balance
array1d< real64 > localResidualNorm;
array1d< real64 > localResidualNormalizer;
if( isThermal() )
{
- numNorm = 2; // mass balance and energy balance
+ numNorm = 2; // mass balance and energy balance
}
localResidualNorm.resize( numNorm );
localResidualNormalizer.resize( numNorm );
@@ -928,51 +1305,54 @@ SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
WellControls const & wellControls = getWellControls( subRegion );
- // step 1: compute the norm in the subRegion
- if( isThermal() )
+ if( wellControls.isWellOpen() )
{
- real64 subRegionResidualNorm[2]{};
- thermalSinglePhaseWellKernels::ResidualNormKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( rankOffset,
- wellDofKey,
- localRhs,
- subRegion,
- fluid,
- wellControls,
- time_n,
- dt,
- m_nonlinearSolverParameters.m_minNormalizer,
- subRegionResidualNorm );
- // step 2: reduction across meshBodies/regions/subRegions
-
- for( integer i=0; i localResidualNorm[i] )
+ real64 subRegionResidualNorm[2]{};
+ thermalSinglePhaseWellKernels::ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ for( integer i=0; i localResidualNorm[i] )
+ {
+ localResidualNorm[i] = subRegionResidualNorm[i];
+ }
}
}
- }
- else
- {
- real64 subRegionResidualNorm[1]{};
- ResidualNormKernelFactory::
- createAndLaunch< parallelDevicePolicy<> >( rankOffset,
- wellDofKey,
- localRhs,
- subRegion,
- fluid,
- wellControls,
- time_n,
- dt,
- m_nonlinearSolverParameters.m_minNormalizer,
- subRegionResidualNorm );
-
- // step 2: reduction across meshBodies/regions/subRegions
-
- if( subRegionResidualNorm[0] > localResidualNorm[0] )
+ else
{
- localResidualNorm[0] = subRegionResidualNorm[0];
+ real64 subRegionResidualNorm[1]{};
+ ResidualNormKernelFactory::
+ createAndLaunch< parallelDevicePolicy<> >( rankOffset,
+ wellDofKey,
+ localRhs,
+ subRegion,
+ fluid,
+ wellControls,
+ time_n,
+ dt,
+ m_nonlinearSolverParameters.m_minNormalizer,
+ subRegionResidualNorm );
+
+ // step 2: reduction across meshBodies/regions/subRegions
+
+ if( subRegionResidualNorm[0] > localResidualNorm[0] )
+ {
+ localResidualNorm[0] = subRegionResidualNorm[0];
+ }
}
}
} );
@@ -1003,6 +1383,47 @@ SinglePhaseWell::calculateResidualNorm( real64 const & time_n,
return resNorm;
}
+bool SinglePhaseWell::checkWellSystemSolution( ElementSubRegionBase & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor )
+{
+ GEOS_MARK_FUNCTION;
+
+ string const wellDofKey = dofManager.getKey( wellElementDofName() );
+ integer numNegativePressures = 0;
+ real64 minPressure = 0.0;
+
+
+ globalIndex const rankOffset = dofManager.rankOffset();
+ // get the degree of freedom numbers on well elements
+ arrayView1d< globalIndex const > const & dofNumber =
+ subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< integer const > const & ghostRank = subRegion.ghostRank();
+
+ // get a reference to the primary variables on well elements
+ arrayView1d< real64 const > const & pres =
+ subRegion.getField< well::pressure >();
+
+ auto const statistics =
+ singlePhaseBaseKernels::SolutionCheckKernel::
+ launch< parallelDevicePolicy<> >( localSolution, rankOffset, dofNumber, ghostRank, pres, scalingFactor );
+
+ numNegativePressures += statistics.first;
+ minPressure = std::min( minPressure, statistics.second );
+
+
+ numNegativePressures = MpiWrapper::sum( numNegativePressures );
+
+ if( numNegativePressures > 0 )
+ {
+ GEOS_LOG_LEVEL_RANK_0( logInfo::Solution,
+ GEOS_FMT( " {}: Number of negative pressure values: {}, minimum value: {} Pa",
+ getName(), numNegativePressures, fmt::format( "{:.{}f}", minPressure, 3 ) ) );
+ }
+
+ return (m_allowNegativePressure || numNegativePressures == 0) ? 1 : 0;
+}
bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain,
DofManager const & dofManager,
@@ -1037,7 +1458,7 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain,
arrayView1d< real64 const > const & pres =
subRegion.getField< well::pressure >();
- auto const statistics =
+ std::pair< integer, real64 > statistics =
singlePhaseBaseKernels::SolutionCheckKernel::
launch< parallelDevicePolicy<> >( localSolution, rankOffset, dofNumber, ghostRank, pres, scalingFactor );
@@ -1058,6 +1479,66 @@ bool SinglePhaseWell::checkSystemSolution( DomainPartition & domain,
return (m_allowNegativePressure || numNegativePressures == 0) ? 1 : 0;
}
+void
+SinglePhaseWell::applyWellSystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ WellElementSubRegion & subRegion )
+{
+ GEOS_UNUSED_VAR( dt );
+ GEOS_UNUSED_VAR( subRegion );
+ DofManager::CompMask pressureMask( m_numDofPerWellElement, 0, 1 );
+ DofManager::CompMask connRateMask( m_numDofPerWellElement, 1, 2 );
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ well::pressure::key(),
+ scalingFactor,
+ pressureMask );
+
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ well::connectionRate::key(),
+ scalingFactor,
+ connRateMask );
+
+ if( isThermal() )
+ {
+ DofManager::CompMask temperatureMask( m_numDofPerWellElement, 2, 3 );
+
+ dofManager.addVectorToField( localSolution,
+ wellElementDofName(),
+ fields::well::temperature::key(),
+ scalingFactor,
+ temperatureMask );
+
+ }
+
+
+ FieldIdentifiers fieldsToBeSync;
+ if( isThermal() )
+ {
+ fieldsToBeSync.addElementFields( { well::pressure::key(),
+ well::connectionRate::key(),
+ well::temperature::key() },
+ getTargetRegionNames() );
+ }
+ else
+ {
+ fieldsToBeSync.addElementFields( { well::pressure::key(),
+ well::connectionRate::key() },
+ getTargetRegionNames() );
+ }
+ CommunicationTools::getInstance().synchronizeFields( fieldsToBeSync,
+ mesh,
+ domain.getNeighbors(),
+ true );
+
+
+}
+
void
SinglePhaseWell::applySystemSolution( DofManager const & dofManager,
arrayView1d< real64 const > const & localSolution,
@@ -1157,6 +1638,26 @@ void SinglePhaseWell::resetStateToBeginningOfStep( DomainPartition & domain )
} );
}
+void SinglePhaseWell::saveState( WellElementSubRegion & subRegion )
+{
+ arrayView1d< real64 const > const wellElemPressure = subRegion.getField< well::pressure >();
+ arrayView1d< real64 > const wellElemPressure_n = subRegion.getField< well::pressure_n >();
+ wellElemPressure_n.setValues< parallelDevicePolicy<> >( wellElemPressure );
+
+ if( isThermal() )
+ {
+ arrayView1d< real64 const > const wellElemTemperature = subRegion.getField< well::temperature >();
+ arrayView1d< real64 > const wellElemTemperature_n = subRegion.getField< well::temperature_n >();
+ wellElemTemperature_n.setValues< parallelDevicePolicy<> >( wellElemTemperature );
+ }
+ arrayView1d< real64 const > const connRate = subRegion.getField< well::connectionRate >();
+ arrayView1d< real64 > const connRate_n = subRegion.getField< well::connectionRate_n >();
+ connRate_n.setValues< parallelDevicePolicy<> >( connRate );
+
+ SingleFluidBase const & fluid =
+ getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) );
+ fluid.saveConvergedState();
+}
void SinglePhaseWell::implicitStepSetup( real64 const & time,
real64 const & dt,
@@ -1300,5 +1801,66 @@ void SinglePhaseWell::printRates( real64 const & time_n,
} );
}
+bool SinglePhaseWell::evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion )
+{
+ WellControls & wellControls = getWellControls( subRegion );
+ // create list of all constraints to process
+ std::vector< WellConstraintBase * > constraintList;
+ if( wellControls.isProducer() )
+ {
+ constraintList = wellControls.getProdRateConstraints();
+ // Solve minimum bhp constraint first
+ constraintList.insert( constraintList.begin(), wellControls.getMinBHPConstraint() );
+ }
+ else
+ {
+ constraintList = wellControls.getInjRateConstraints();
+ // Solve maximum bhp constraint first;
+ constraintList.insert( constraintList.begin(), wellControls.getMaxBHPConstraint() );
+ }
+ // Get current constraint
+ WellConstraintBase * limitingConstraint = nullptr;
+ for( auto & constraint : constraintList )
+ {
+ if( constraint->getName() == wellControls.getCurrentConstraint()->getName())
+ {
+ limitingConstraint = constraint;
+ // tjb. this is likely not needed. set in update state
+ constraint->setBHP ( wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() ));
+ constraint->setTotalVolumeRate ( wellControls.getReference< real64 >(
+ SinglePhaseWell::viewKeyStruct::currentVolRateString() ));
+
+ GEOS_LOG_RANK_IF ( getLogLevel() > 4 && subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " Limiting Constraint " << limitingConstraint->getName() << " " << limitingConstraint->bottomHolePressure() << " " <<
+ limitingConstraint->totalVolumeRate() );
+ }
+ }
+
+
+ // Check current against other constraints
+ for( auto & constraint : constraintList )
+ {
+
+ if( limitingConstraint->getName() != constraint->getName())
+ {
+ //std::cout << "Use estimator " << useEstimator << " Evaluating constraint " << constraint.getName() << " against constraint " <<
+ // limitingConstraint->getName() << std::endl;
+ if( constraint->checkViolation( *limitingConstraint, time_n ) )
+ {
+ wellControls.setControl( static_cast< WellControls::Control >(constraint->getControl()) ); // tjb old
+ wellControls.setCurrentConstraint( constraint );
+ GEOS_LOG_RANK_IF ( getLogLevel() > 4 && subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " New Limiting Constraint " << constraint->getName() << " " << constraint->getConstraintValue( time_n ) );
+ }
+ }
+ }
+ GEOS_LOG_RANK_IF ( getLogLevel() > 4 && subRegion.isLocallyOwned(),
+ " Well " << subRegion.getName() << " Limiting Constraint " << limitingConstraint->getName() << " " << limitingConstraint->bottomHolePressure() << " " << limitingConstraint->phaseVolumeRates() << " " <<
+ limitingConstraint->totalVolumeRate() << " " << limitingConstraint->massRate());
+
+ return true;
+}
+
REGISTER_CATALOG_ENTRY( PhysicsSolverBase, SinglePhaseWell, string const &, Group * const )
}// namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp
index 7bfeb996aa4..fc3b259bc95 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp
@@ -95,6 +95,15 @@ class SinglePhaseWell : public WellSolverBase
*/
/**@{*/
+ virtual real64 scalingForWellSystemSolution( ElementSubRegionBase & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution ) override;
+ virtual real64
+ calculateWellResidualNorm( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localRhs ) override;
virtual real64
calculateResidualNorm( real64 const & time_n,
real64 const & dt,
@@ -102,6 +111,12 @@ class SinglePhaseWell : public WellSolverBase
DofManager const & dofManager,
arrayView1d< real64 const > const & localRhs ) override;
+ virtual bool
+ checkWellSystemSolution( ElementSubRegionBase & subRegion,
+ DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor ) override;
+
virtual bool
checkSystemSolution( DomainPartition & domain,
DofManager const & dofManager,
@@ -109,6 +124,14 @@ class SinglePhaseWell : public WellSolverBase
real64 const scalingFactor ) override;
virtual void
+ applyWellSystemSolution( DofManager const & dofManager,
+ arrayView1d< real64 const > const & localSolution,
+ real64 const scalingFactor,
+ real64 const dt,
+ DomainPartition & domain,
+ MeshLevel & mesh,
+ WellElementSubRegion & subRegion ) override;
+ virtual void
applySystemSolution( DofManager const & dofManager,
arrayView1d< real64 const > const & localSolution,
real64 const scalingFactor,
@@ -142,7 +165,7 @@ class SinglePhaseWell : public WellSolverBase
* @brief Recompute the volumetric rate that are used in the well constraints
* @param subRegion the well subregion containing all the primary and dependent fields
*/
- virtual void updateVolRateForConstraint( WellElementSubRegion & subRegion );
+ virtual void calculateReferenceElementRates( WellElementSubRegion & subRegion );
/**
* @brief Recompute the BHP pressure that is used in the well constraints
@@ -155,6 +178,11 @@ class SinglePhaseWell : public WellSolverBase
* @param subRegion the well subRegion containing the well elements and their associated fields
*/
virtual void updateFluidModel( WellElementSubRegion & subRegion ) const;
+ /**
+ * @brief Update separator model state
+ * @param subRegion the well subRegion containing the separator
+ */
+ void updateSeparator( WellElementSubRegion & subRegion );
/**
* @brief Recompute the perforation rates for all the wells
@@ -163,6 +191,14 @@ class SinglePhaseWell : public WellSolverBase
virtual void computePerforationRates( real64 const & time_n,
real64 const & dt, DomainPartition & domain ) override;
+ /**
+ * @brief Recompute all dependent quantities from primary variables (including constitutive
+ * models)
+ * @param domain the domain containing the mesh and fields
+ */
+ virtual real64 updateWellState( WellElementSubRegion & subRegion ) override;
+ virtual void updateState( DomainPartition & domain ) override;
+
/**
* @brief Recompute all dependent quantities from primary variables (including constitutive models) on the well
* @param subRegion the well subRegion containing the well elements and their associated fields
@@ -185,6 +221,21 @@ class SinglePhaseWell : public WellSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) override;
+ /**
+ * @brief assembles the flux terms for all connections between well elements
+ * @param time_n previous time value
+ * @param dt time step
+ * @param domain the physical domain object
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param matrix the system matrix
+ * @param rhs the system right-hand side vector
+ */
+ virtual void assembleWellFluxTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
/**
* @brief assembles the flux terms for all connections between well elements
* @param time_n previous time value
@@ -208,6 +259,14 @@ class SinglePhaseWell : public WellSolverBase
* @param matrix the system matrix
* @param rhs the system right-hand side vector
*/
+
+ virtual void assembleWellAccumulationTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
virtual void assembleAccumulationTerms( real64 const & time_n,
real64 const & dt, DomainPartition & domain,
DofManager const & dofManager,
@@ -226,6 +285,22 @@ class SinglePhaseWell : public WellSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs );
+ virtual void assembleWellConstraintTerms( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+
+ virtual void assembleWellPressureRelations( real64 const & time_n,
+ real64 const & dt,
+ WellElementSubRegion const & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) override;
+
+
/**
* @brief assembles the pressure relations at all connections between well elements except at the well head
* @param time_n time at the beginning of the time step
@@ -242,6 +317,13 @@ class SinglePhaseWell : public WellSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) override;
+ /**
+ * @brief Initialize all the primary and secondary variables in all the wells
+ * @param domain the domain containing the well manager to access individual wells
+ */
+ void initializeWells( DomainPartition & domain, real64 const & time_n ) override;
+ void initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n ) override;
+
/*
* @brief apply a special treatment to the wells that are shut
* @param time_n the time at the previous converged time step
@@ -268,6 +350,10 @@ class SinglePhaseWell : public WellSolverBase
protected:
+ virtual void initializePostInitialConditionsPreSubGroups() override;
+
+ void saveState( WellElementSubRegion & subRegion );
+
void printRates( real64 const & time_n,
real64 const & dt,
DomainPartition & domain ) override;
@@ -279,11 +365,6 @@ class SinglePhaseWell : public WellSolverBase
virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override;
- /**
- * @brief Initialize all the primary and secondary variables in all the wells
- * @param domain the domain containing the well manager to access individual wells
- */
- void initializeWells( DomainPartition & domain, real64 const & time_n ) override;
/**
* @brief Make sure that the well constraints are compatible
@@ -297,6 +378,14 @@ class SinglePhaseWell : public WellSolverBase
WellElementSubRegion const & subRegion,
ElementRegionManager const & elemManager ) override;
+ virtual bool evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion ) override;
+
+ /**
+ * @brief Create well separator
+ */
+ void createSeparator();
+
};
} // namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellBHPConstraints.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellBHPConstraints.cpp
new file mode 100644
index 00000000000..70f6e79b86a
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellBHPConstraints.cpp
@@ -0,0 +1,116 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellBHPConstraints.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellBHPConstraints.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+BHPConstraint::BHPConstraint( string const & name, Group * const parent )
+ : WellConstraintBase( name, parent ),
+ m_refElevation( 0.0 ),
+ m_refGravCoef( 0.0 )
+{
+ setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
+
+ registerWrapper( viewKeyStruct::targetBHPString(), &m_constraintValue ).
+ setDefaultValue( 0.0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::WRITE_AND_READ ).
+ setDescription( "Minimun bottom-hole production pressure [Pa]" );
+
+ registerWrapper( viewKeyStruct::refElevString(), &m_refElevation ).
+ setDefaultValue( -1 ).
+ setInputFlag( InputFlags::REQUIRED ).
+ setDescription( "Reference elevation where BHP control is enforced [m]" );
+
+}
+
+
+BHPConstraint::~BHPConstraint()
+{}
+
+void BHPConstraint::postInputInitialization()
+{
+
+ WellConstraintBase::postInputInitialization();
+
+}
+
+MinimumBHPConstraint::MinimumBHPConstraint( string const & name, Group * const parent )
+ : BHPConstraint( name, parent )
+{
+ setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
+
+ registerWrapper( viewKeyStruct::targetBHPString(), &m_constraintValue ).
+ setDefaultValue( 0.0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::WRITE_AND_READ ).
+ setDescription( "Minimun bottom-hole production pressure [Pa]" );
+}
+
+
+MinimumBHPConstraint::~MinimumBHPConstraint()
+{}
+
+void MinimumBHPConstraint::postInputInitialization()
+{
+
+ BHPConstraint::postInputInitialization();
+
+}
+
+bool MinimumBHPConstraint::checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const
+{
+ return currentConstraint.bottomHolePressure() < getConstraintValue( currentTime );
+}
+
+MaximumBHPConstraint::MaximumBHPConstraint( string const & name, Group * const parent )
+ : BHPConstraint( name, parent )
+{
+ setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
+
+}
+
+
+MaximumBHPConstraint::~MaximumBHPConstraint()
+{}
+
+void MaximumBHPConstraint::postInputInitialization()
+{
+ // Validate value and table options
+ BHPConstraint::postInputInitialization();
+
+}
+bool MaximumBHPConstraint::checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const
+{
+ return currentConstraint.bottomHolePressure() > getConstraintValue( currentTime );
+}
+
+REGISTER_CATALOG_ENTRY( WellConstraintBase, MinimumBHPConstraint, string const &, Group * const )
+REGISTER_CATALOG_ENTRY( WellConstraintBase, MaximumBHPConstraint, string const &, Group * const )
+
+} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp
new file mode 100644
index 00000000000..3002d303e39
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellBHPConstraints.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 TotalEnergies
+ * 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 WellBHPConstraints.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLBHPCONSTRAINTS_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLBHPCONSTRAINTS_HPP
+
+#include "common/format/EnumStrings.hpp"
+#include "dataRepository/Group.hpp"
+#include "functions/TableFunction.hpp"
+#include "WellConstraintsBase.hpp"
+namespace geos
+{
+
+/**
+ * @class BHPConstraint
+ * @brief This class describes a minimum pressure constraint used to control a injection well.
+ */
+class BHPConstraint : public WellConstraintBase
+{
+public:
+
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit BHPConstraint( string const & name, dataRepository::Group * const parent );
+
+
+ /**
+ * @brief Default destructor.
+ */
+ ~BHPConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ BHPConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ BHPConstraint( BHPConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ BHPConstraint( BHPConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ BHPConstraint & operator=( BHPConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ BHPConstraint & operator=( BHPConstraint && ) = delete;
+
+ ///@}
+
+ /**
+ * @name Getters / Setters
+ */
+ ///@{
+
+ // Temp interface - tjb
+ virtual ConstraintTypeId getControl() const override { return ConstraintTypeId::BHP; };
+
+ ///@}
+ /**
+ * @brief Struct to serve as a container for variable strings and keys.
+ * @struct viewKeyStruct
+ */
+ struct viewKeyStruct
+ {
+ /// String key for the well target BHP
+ static constexpr char const * targetBHPString() { return "targetBHP"; }
+ /// String key for the well reference elevation (for BHP control)
+ static constexpr char const * refElevString() { return "referenceElevation"; }
+ }
+ viewKeysWellBHPConstraint;
+
+ //virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const override;
+
+ /**
+ * @brief Getter for the reference elevation where the BHP control is enforced
+ * @return the reference elevation
+ */
+ real64 getReferenceElevation() const { return m_refElevation; }
+
+ /**
+ * @brief Set the reference elevation where the BHP control is enforced
+ * @return the reference elevation
+ */
+ void setReferenceElevation( real64 const & refElevation ) { m_refElevation=refElevation; }
+
+ /**
+ * @brief Getter for the reference gravity coefficient
+ * @return the reference gravity coefficient
+ */
+ real64 getReferenceGravityCoef() const { return m_refGravCoef; }
+
+ /**
+ * @brief Setter for the reference gravity
+ */
+ void setReferenceGravityCoef( real64 const & refGravCoef ) { m_refGravCoef = refGravCoef; }
+
+protected:
+
+ virtual void postInputInitialization() override;
+
+ /// Reference elevation
+ real64 m_refElevation;
+
+ /// Gravity coefficient of the reference elevation
+ real64 m_refGravCoef;
+
+};
+
+/**
+ * @class MinimumBHPConstraint
+ * @brief This class describes a minimum pressure constraint used to control a injection well.
+ */
+class MinimumBHPConstraint : public BHPConstraint
+{
+public:
+
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit MinimumBHPConstraint( string const & name, dataRepository::Group * const parent );
+
+
+ /**
+ * @brief Default destructor.
+ */
+ ~MinimumBHPConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ MinimumBHPConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ MinimumBHPConstraint( MinimumBHPConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ MinimumBHPConstraint( MinimumBHPConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ MinimumBHPConstraint & operator=( MinimumBHPConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ MinimumBHPConstraint & operator=( MinimumBHPConstraint && ) = delete;
+
+ ///@}
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "MinimumBHPConstraint";
+ }
+ virtual string getCatalogName() const override { return catalogName(); }
+ /**
+ * @name Getters / Setters
+ */
+ ///@{
+
+
+ /**
+ * @brief Struct to serve as a container for variable strings and keys.
+ * @struct viewKeyStruct
+ */
+ struct viewKeyStruct
+ {
+ /// String key for the well target BHP
+ static constexpr char const * targetBHPString() { return "targetBHP"; }
+ }
+ viewKeysWellBHPConstraint;
+
+ virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const override;
+
+protected:
+
+ virtual void postInputInitialization() override;
+
+
+};
+
+/**
+ * @class WellMinimumBHPConstraint
+ * @brief This class describes a maximum pressure constraint used to control a injection well.
+ */
+class MaximumBHPConstraint : public BHPConstraint
+{
+public:
+
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit MaximumBHPConstraint( string const & name, dataRepository::Group * const parent );
+
+
+ /**
+ * @brief Default destructor.
+ */
+ ~MaximumBHPConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ MaximumBHPConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ MaximumBHPConstraint( MaximumBHPConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ MaximumBHPConstraint( MaximumBHPConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ MaximumBHPConstraint & operator=( MaximumBHPConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ MaximumBHPConstraint & operator=( MaximumBHPConstraint && ) = delete;
+
+ ///@}
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "MaximumBHPConstraint";
+ }
+ virtual string getCatalogName() const override { return catalogName(); }
+ /**
+ * @name Getters / Setters
+ */
+ ///@{
+ // Temp interface - tjb
+ virtual ConstraintTypeId getControl() const override { return ConstraintTypeId::BHP; };
+
+
+ ///@}
+ /**
+ * @brief Struct to serve as a container for variable strings and keys.
+ * @struct viewKeyStruct
+ */
+ struct viewKeyStruct
+ {
+ /// String key for the well target BHP
+ static constexpr char const * targetBHPString() { return "targetBHP"; }
+ }
+ viewKeysWellBHPConstraint;
+
+ virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const override;
+protected:
+
+ virtual void postInputInitialization() override;
+
+
+
+private:
+
+
+};
+
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLBHPCONSTRAINTS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp
index 58b8b421c3a..83eadb7c2ff 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstants.hpp
@@ -36,6 +36,11 @@ struct WellConstants
static constexpr real64 defaultInjectorBHP = 1.01325e8;
};
+enum class WellTypes : integer
+{
+ PRODUCER, /**< A production well */
+ INJECTOR /**< An injection well */
+};
} //namespace geos
#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTANTS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.cpp
new file mode 100644
index 00000000000..cdc89300129
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.cpp
@@ -0,0 +1,134 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellConstraintBase.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellConstraintsBase.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+// Provide a properly-typed static catalog for WellConstraintBase so that
+// CatalogInterface< WellConstraintBase, ... >::getCatalog() can return
+// a catalog of CatalogInterface objects instead of
+// inheriting Group::getCatalog() which returns a catalog of Group entries.
+WellConstraintBase::CatalogInterface::CatalogType & WellConstraintBase::getCatalog()
+{
+ static WellConstraintBase::CatalogInterface::CatalogType catalog;
+ return catalog;
+}
+
+namespace
+{
+
+
+#if 0
+/// Utility function to create a one-value table internally when not provided by the user
+TableFunction * createConstraintScheduleTable( string const & tableName,
+ real64 const & constantValue )
+{
+ array1d< array1d< real64 > > timeCoord;
+ timeCoord.resize( 1 );
+ timeCoord[0].emplace_back( 0 );
+ array1d< real64 > constantValueArray;
+ constantValueArray.emplace_back( constantValue );
+
+ FunctionManager & functionManager = FunctionManager::getInstance();
+ TableFunction * table = dynamicCast< TableFunction * >( functionManager.createChild( TableFunction::catalogName(), tableName ));
+ table->setTableCoordinates( timeCoord, { units::Time } );
+ table->setTableValues( constantValueArray );
+ table->setInterpolationMethod( TableFunction::InterpolationType::Lower );
+ return table;
+}
+#endif
+
+
+}
+
+WellConstraintBase::WellConstraintBase( string const & name, Group * const parent )
+ : Group( name, parent ),
+ m_isConstraintActive( true ),
+ m_useScheduleTable( false ),
+ m_constraintValue( 0 ),
+ m_constraintScheduleTable( nullptr ),
+ m_rateSign( 1.0 ) // Default to positive rate sign for injection, set to -1.0 for production wells
+
+{
+ setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
+
+ registerWrapper( viewKeyStruct::constraintScheduleTableNameString(), &m_constraintScheduleTableName ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Name of the well constraint schedule table when the constraint value is a time dependent function. \n" );
+
+}
+
+
+WellConstraintBase::~WellConstraintBase()
+{}
+
+
+void WellConstraintBase::postInputInitialization()
+{
+
+ GEOS_THROW_IF( ((m_constraintValue > 0.0 && !m_constraintScheduleTableName.empty())|| (!(m_constraintValue > 0.0) && m_constraintScheduleTableName.empty())),
+ this->getDataContext() << ": You have provided redundant information for well constraint value ." <<
+ " A constraint value and table of constraint values cannot be specified together",
+ InputError );
+
+ // Create time-dependent constraint table
+ if( !m_constraintScheduleTableName.empty() )
+ {
+ FunctionManager & functionManager = FunctionManager::getInstance();
+ m_constraintScheduleTable = &(functionManager.getGroup< TableFunction const >( m_constraintScheduleTableName ));
+
+ GEOS_THROW_IF( m_constraintScheduleTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower,
+ this->getName() << " " << this->getDataContext() << ": The interpolation method for the schedule table "
+ << m_constraintScheduleTable->getName() << " should be TableFunction::InterpolationType::Lower",
+ InputError );
+ }
+
+}
+
+void WellConstraintBase::setNextDtFromTables( real64 const currentTime, real64 & nextDt )
+{
+ setNextDtFromTable( m_constraintScheduleTable, currentTime, nextDt );
+}
+
+void WellConstraintBase::setNextDtFromTable( TableFunction const * table, real64 const currentTime, real64 & nextDt )
+{
+ if( table )
+ {
+ // small epsilon to make sure we land on the other side of table interval and pick up the right rate
+ real64 const eps = 1e-6;
+ real64 const dtLimit = (table->getCoord( ¤tTime, 0, TableFunction::InterpolationType::Upper ) - currentTime) * ( 1.0 + eps );
+ if( dtLimit > eps && dtLimit < nextDt )
+ {
+ nextDt = dtLimit;
+ }
+ }
+}
+
+
+} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp
new file mode 100644
index 00000000000..586f61a17d3
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp
@@ -0,0 +1,289 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellConstraintBase.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINTBASE_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINTBASE_HPP
+
+#include "common/format/EnumStrings.hpp"
+
+#include "functions/TableFunction.hpp"
+#include "dataRepository/Group.hpp"
+namespace geos
+{
+
+
+
+enum class ConstraintTypeId : integer
+{
+ BHP, /**< The well operates at a specified bottom hole pressure (BHP) */
+ PHASEVOLRATE, /**< The well operates at a specified phase volumetric flow rate */
+ TOTALVOLRATE, /**< The well operates at a specified total volumetric flow rate */
+ MASSRATE, /**;
+
+ /// Get the singleton catalog for WellConstraintBase
+ static CatalogInterface::CatalogType & getCatalog();
+
+ /**
+ * @brief function to return the catalog name of the derived class
+ * @return a string that contains the catalog name of the derived class
+ */
+ virtual string getCatalogName() const = 0;
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit WellConstraintBase( string const & name, dataRepository::Group * const parent );
+
+
+ /**
+ * @brief Default destructor.
+ */
+ ~WellConstraintBase() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ WellConstraintBase() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ WellConstraintBase( WellConstraintBase const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ WellConstraintBase( WellConstraintBase && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ WellConstraintBase & operator=( WellConstraintBase const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ WellConstraintBase & operator=( WellConstraintBase && ) = delete;
+
+ ///@}
+
+
+ /**
+ * @name Getters / Setters
+ */
+ ///@{
+
+ // Temp interface - tjb
+ virtual ConstraintTypeId getControl() const = 0;
+
+ /**
+ * @brief Defines whether the constraint should be evaluated or not
+ * @brief Some workflows require the well model to define a constraint
+ * @brief of similar type to user defined constraints. For example,
+ * @brief rate constraints to evaluated WHP constraints.
+ * @return true if the constraint is active, false otherwise
+ */
+ bool isConstraintActive( ) const { return m_isConstraintActive; }
+
+ /**
+ * @brief Sets constraint active status
+ * @param[in] constraintActive true if the constraint is active, false otherwise
+ */
+ bool setConstraintActive( bool const & constraintActive ) { return m_isConstraintActive=constraintActive; }
+
+ /**
+ * @brief Sets constraint value
+ * @param[in] constraint value
+ */
+ void setConstraintValue( real64 const & constraintValue )
+ {
+ m_constraintValue = constraintValue;
+ }
+
+ /**
+ * @brief Get the target bottom hole pressure value.
+ * @return a value for the target bottom hole pressure
+ */
+ real64 getConstraintValue( real64 const & currentTime ) const
+ {
+ if( m_constraintScheduleTableName.empty() )
+ {
+ return m_rateSign*m_constraintValue;
+ }
+
+ return m_rateSign*m_constraintScheduleTable->evaluate( ¤tTime );
+ }
+
+ ///@}
+
+ /**
+ * @brief Struct to serve as a container for variable strings and keys.
+ * @struct viewKeyStruct
+ */
+ struct viewKeyStruct
+ {
+ /// string key for schedule table name
+ static constexpr char const * constraintScheduleTableNameString() { return "constraintScheduleTableName"; }
+
+ /// String key for the well constraint value
+ static constexpr char const * constraintValueString() { return "constraintValue"; }
+
+
+ }
+ /// ViewKey struct for the WellControls class
+ viewKeysWellConstraint;
+
+ // Quantities computed from well constraint solve with this boundary condition
+ // This needs to be somewhere else tjb
+ void setBHP( real64 bhp ){ m_BHP=bhp;};
+ void setPhaseVolumeRates( array1d< real64 > const & phaseVolumeRates ) { m_phaseVolumeRates = phaseVolumeRates; };
+ void setTotalVolumeRate( real64 totalVolumeRate ){ m_totalVolumeRate = totalVolumeRate; };
+ void setMassRate( real64 massRate ){ m_massRate = massRate; };
+
+ /**
+ * @brief Getter for the bottom hole pressure
+ * @return bottom hole pressure
+ */
+ real64 bottomHolePressure() const { return m_BHP; }
+
+ /**
+ * @brief Getter for the phase volume rates
+ * @return an arrayView1d storing the phase volume rates
+ */
+ arrayView1d< real64 const > phaseVolumeRates() const { return m_phaseVolumeRates; }
+
+ /**
+ * @brief Getter for the total volume rate
+ * @return mass rate
+ */
+ real64 totalVolumeRate() const { return m_totalVolumeRate; }
+
+ /**
+ * @brief Getter for the liquid rate
+ * @return liquid rate
+ */
+ real64 liquidRate() const { return m_liquidRate; }
+
+ /**
+ * @brief Getter for the mass rate
+ * @return mass rate
+ */
+ real64 massRate() const { return m_massRate; }
+
+ // endof This needs to be somewhere else tjb
+ /**
+ * @brief Check if this constraint is violated
+ * @return true if limiting constraint, false otherwise
+ */
+ virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const = 0;
+
+protected:
+
+ virtual void postInputInitialization() override;
+
+ /**
+ * @brief set next time step based on tables intervals
+ * @param[in] currentTime the current time
+ * @param[inout] nextDt the time step
+ */
+ void setNextDtFromTables( real64 const currentTime, real64 & nextDt );
+
+
+protected:
+
+ /// Constraint status
+ bool m_isConstraintActive;
+
+ /// Flag to indicate whether a schedule table should be generated for constraint value;
+ bool m_useScheduleTable;
+
+ /// Constraint value
+ real64 m_constraintValue;
+
+ void setNextDtFromTable( TableFunction const * table, real64 const currentTime, real64 & nextDt );
+
+ /// Constraint schedule table name
+ string m_constraintScheduleTableName;
+
+ /// Constraint values versus time
+ TableFunction const * m_constraintScheduleTable;
+
+ // Quantities computed from well constraint solve with this boundary condition
+
+ // botton hole pressure
+ real64 m_BHP;
+
+ // phase rates
+ array1d< real64 > m_phaseVolumeRates;
+
+ // liquid rate
+ real64 m_liquidRate;
+
+ // total volume rate
+ real64 m_totalVolumeRate;
+
+ // mass rate
+ real64 m_massRate;
+
+ /// Rate sign. +1 for injector, -1 for producer
+ real64 m_rateSign;
+};
+
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINTBASE_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp
index 098d80beac0..5d69896b204 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp
@@ -32,24 +32,18 @@ using namespace dataRepository;
WellControls::WellControls( string const & name, Group * const parent )
: Group( name, parent ),
m_type( Type::PRODUCER ),
- m_refElevation( 0.0 ),
- m_refGravCoef( 0.0 ),
m_inputControl( Control::UNINITIALIZED ),
- m_currentControl( Control::UNINITIALIZED ),
- m_targetBHP( 0.0 ),
- m_targetTotalRate( 0.0 ),
- m_targetPhaseRate( 0.0 ),
- m_targetMassRate( 0.0 ),
+ m_currentControl( Control::UNINITIALIZED ), // tjb remove
m_useSurfaceConditions( 0 ),
- m_surfacePres( 0.0 ),
- m_surfaceTemp( 0.0 ),
+ m_surfacePres( -1.0 ),
+ m_surfaceTemp( -1.0 ),
m_isCrossflowEnabled( 1 ),
m_initialPressureCoefficient( 0.1 ),
m_rateSign( -1.0 ),
- m_targetTotalRateTable( nullptr ),
- m_targetPhaseRateTable( nullptr ),
- m_targetBHPTable( nullptr ),
m_statusTable( nullptr ),
+ m_wellOpen( false ),
+ m_constraintSwitch( true ),
+ m_currentConstraint( nullptr ),
m_wellStatus( WellControls::Status::OPEN ),
m_regionAveragePressure( -1 )
{
@@ -59,61 +53,14 @@ WellControls::WellControls( string const & name, Group * const parent )
setInputFlag( InputFlags::REQUIRED ).
setDescription( "Well type. Valid options:\n* " + EnumStrings< Type >::concat( "\n* " ) );
- registerWrapper( viewKeyStruct::inputControlString(), &m_inputControl ).
- setInputFlag( InputFlags::REQUIRED ).
- setDescription( "Well control. Valid options:\n* " + EnumStrings< Control >::concat( "\n* " ) );
-
registerWrapper( viewKeyStruct::currentControlString(), &m_currentControl ).
setDefaultValue( Control::UNINITIALIZED ).
setInputFlag( InputFlags::FALSE ).
setDescription( "Current well control" );
- registerWrapper( viewKeyStruct::targetBHPString(), &m_targetBHP ).
- setDefaultValue( 0.0 ).
- setInputFlag( InputFlags::OPTIONAL ).
- setRestartFlags( RestartFlags::WRITE_AND_READ ).
- setDescription( "Target bottom-hole pressure [Pa]" );
-
- registerWrapper( viewKeyStruct::targetTotalRateString(), &m_targetTotalRate ).
- setDefaultValue( 0.0 ).
- setInputFlag( InputFlags::OPTIONAL ).
- setRestartFlags( RestartFlags::WRITE_AND_READ ).
- setDescription( "Target total volumetric rate (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s])" );
-
- registerWrapper( viewKeyStruct::targetPhaseRateString(), &m_targetPhaseRate ).
- setDefaultValue( 0.0 ).
- setInputFlag( InputFlags::OPTIONAL ).
- setRestartFlags( RestartFlags::WRITE_AND_READ ).
- setDescription( "Target phase volumetric rate (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s])" );
-
- registerWrapper( viewKeyStruct::targetMassRateString(), &m_targetMassRate ).
- setDefaultValue( 0.0 ).
- setInputFlag( InputFlags::OPTIONAL ).
- setRestartFlags( RestartFlags::WRITE_AND_READ ).
- setDescription( "Target Mass Rate rate ( [kg^3/s])" );
-
- registerWrapper( viewKeyStruct::targetPhaseNameString(), &m_targetPhaseName ).
- setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
- setDefaultValue( "" ).
- setInputFlag( InputFlags::OPTIONAL ).
- setRestartFlags( RestartFlags::WRITE_AND_READ ).
- setDescription( "Name of the target phase" );
-
- registerWrapper( viewKeyStruct::refElevString(), &m_refElevation ).
- setDefaultValue( -1 ).
+ registerWrapper( viewKeyStruct::inputControlString(), &m_inputControl ).
setInputFlag( InputFlags::REQUIRED ).
- setDescription( "Reference elevation where BHP control is enforced [m]" );
-
- registerWrapper( viewKeyStruct::injectionStreamString(), &m_injectionStream ).
- setDefaultValue( -1 ).
- setSizedFromParent( 0 ).
- setInputFlag( InputFlags::OPTIONAL ).
- setDescription( "Global component densities of the injection stream [moles/m^3 or kg/m^3]" );
-
- registerWrapper( viewKeyStruct::injectionTemperatureString(), &m_injectionTemperature ).
- setDefaultValue( -1 ).
- setInputFlag( InputFlags::OPTIONAL ).
- setDescription( "Temperature of the injection stream [K]" );
+ setDescription( "Well control. Valid options:\n* " + EnumStrings< Control >::concat( "\n* " ) );
registerWrapper( viewKeyStruct::useSurfaceConditionsString(), &m_useSurfaceConditions ).
setDefaultValue( 0 ).
@@ -154,31 +101,6 @@ WellControls::WellControls( string const & name, Group * const parent )
" - Injector pressure at reference depth initialized as: (1+initialPressureCoefficient)*reservoirPressureAtClosestPerforation + density*g*( zRef - zPerf ) \n"
" - Producer pressure at reference depth initialized as: (1-initialPressureCoefficient)*reservoirPressureAtClosestPerforation + density*g*( zRef - zPerf ) " );
- registerWrapper( viewKeyStruct::targetBHPTableNameString(), &m_targetBHPTableName ).
- setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
- setInputFlag( InputFlags::OPTIONAL ).
- setDescription( "Name of the BHP table when the rate is a time dependent function" );
-
- registerWrapper( viewKeyStruct::targetTotalRateTableNameString(), &m_targetTotalRateTableName ).
- setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
- setInputFlag( InputFlags::OPTIONAL ).
- setDescription( "Name of the total rate table when the rate is a time dependent function" );
-
- registerWrapper( viewKeyStruct::targetPhaseRateTableNameString(), &m_targetPhaseRateTableName ).
- setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
- setInputFlag( InputFlags::OPTIONAL ).
- setDescription( "Name of the phase rate table when the rate is a time dependent function" );
-
- registerWrapper( viewKeyStruct::targetMassRateTableNameString(), &m_targetMassRateTableName ).
- setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
- setInputFlag( InputFlags::OPTIONAL ).
- setDescription( "Name of the mass rate table when the rate is a time dependent function" );
-
- registerWrapper( viewKeyStruct::statusTableNameString(), &m_statusTableName ).
- setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
- setInputFlag( InputFlags::OPTIONAL ).
- setDescription( "Name of the well status table when the status of the well is a time dependent function. \n"
- "If the status function evaluates to a positive value at the current time, the well will be open otherwise the well will be shut." );
addLogLevel< logInfo::WellControl >();
}
@@ -187,28 +109,80 @@ WellControls::WellControls( string const & name, Group * const parent )
WellControls::~WellControls()
{}
-void WellControls::switchToBHPControl( real64 const & val )
+Group * WellControls::createChild( string const & childKey, string const & childName )
{
- m_currentControl = Control::BHP;
- m_targetBHP = val;
-}
+ GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) );
+ ////const auto childTypes = { viewKeyStruct::perforationString() };
+ //GEOS_ERROR_IF( childKey != viewKeyStruct::perforationString(),
+ // CatalogInterface::unknownTypeError( childKey, getDataContext(), childTypes ) );
-void WellControls::switchToTotalRateControl( real64 const & val )
-{
- m_currentControl = Control::TOTALVOLRATE;
- m_targetTotalRate = val;
-}
+ Group * constraint = nullptr;
+ if( childKey == viewKeyStruct::minimumBHPConstraintString() )
+ {
+ MinimumBHPConstraint & bhpConstraint = registerGroup< MinimumBHPConstraint >( childName );
+ m_minBHPConstraint = &bhpConstraint;
+ constraint = &bhpConstraint;
+ }
+ else if( childKey == viewKeyStruct::maximumBHPConstraintString() )
+ {
+ MaximumBHPConstraint & bhpConstraint = registerGroup< MaximumBHPConstraint >( childName );
+ m_maxBHPConstraint = &bhpConstraint;
+ constraint = &bhpConstraint;
+ }
+ else if( childKey == viewKeyStruct::productionPhaseVolumeRateConstraintString() )
+ {
+ ProductionConstraint< PhaseVolumeRateConstraint > & phaseConstraint = registerGroup< ProductionConstraint< PhaseVolumeRateConstraint > >( childName );
+ m_productionRateConstraintList.emplace_back( &phaseConstraint );
+ constraint = &phaseConstraint;
+ }
+ else if( childKey == viewKeyStruct::injectionPhaseVolumeRateConstraint() )
+ {
-void WellControls::switchToPhaseRateControl( real64 const & val )
-{
- m_currentControl = Control::PHASEVOLRATE;
- m_targetPhaseRate = val;
+ InjectionConstraint< PhaseVolumeRateConstraint > & phaseConstraint = registerGroup< InjectionConstraint< PhaseVolumeRateConstraint > >( childName );
+ m_injectionRateConstraintList.emplace_back( &phaseConstraint );
+ constraint = &phaseConstraint;
+ }
+ else if( childKey == viewKeyStruct::productionVolumeRateConstraint() )
+ {
+ ProductionConstraint< VolumeRateConstraint > & volConstraint = registerGroup< ProductionConstraint< VolumeRateConstraint > >( childName );
+ m_productionRateConstraintList.emplace_back( &volConstraint );
+ constraint = &volConstraint;
+ }
+ else if( childKey == viewKeyStruct::injectionVolumeRateConstraint() )
+ {
+ InjectionConstraint< VolumeRateConstraint > & volConstraint = registerGroup< InjectionConstraint< VolumeRateConstraint > >( childName );
+ m_injectionRateConstraintList.emplace_back( &volConstraint );
+ constraint = &volConstraint;
+ }
+ else if( childKey == viewKeyStruct::productionMassRateConstraint() )
+ {
+ ProductionConstraint< MassRateConstraint > & massConstraint = registerGroup< ProductionConstraint< MassRateConstraint > >( childName );
+ m_productionRateConstraintList.emplace_back( &massConstraint );
+ constraint = &massConstraint;
+
+ }
+ else if( childKey == viewKeyStruct::injectionMassRateConstraint() )
+ {
+ InjectionConstraint< MassRateConstraint > & massConstraint = registerGroup< InjectionConstraint< MassRateConstraint > >( childName );
+ m_injectionRateConstraintList.emplace_back( &massConstraint );
+ constraint = &massConstraint;
+ }
+ else if( childKey == viewKeyStruct::productionLiquidRateConstraint() )
+ {
+ ProductionConstraint< LiquidRateConstraint > & liquidConstraint = registerGroup< ProductionConstraint< LiquidRateConstraint > >( childName );
+ m_productionRateConstraintList.emplace_back( &liquidConstraint );
+ constraint = &liquidConstraint;
+ }
+ return constraint;
}
-void WellControls::switchToMassRateControl( real64 const & val )
+void WellControls::expandObjectCatalogs()
{
- m_currentControl = Control::MASSRATE;
- m_targetMassRate = val;
+ // During schema generation, register one of each type derived from ConstitutiveBase here
+ for( auto & catalogIter: WellConstraintBase::getCatalog())
+ {
+ createChild( catalogIter.first, catalogIter.first );
+ }
}
namespace
@@ -236,6 +210,7 @@ TableFunction * createWellTable( string const & tableName,
void WellControls::postInputInitialization()
{
+
// 0) Assign the value of the current well control
// When the simulation starts from a restart file, we don't want to use the inputControl,
// because the control may have switched in the simulation that generated the restart
@@ -249,119 +224,27 @@ void WellControls::postInputInitialization()
m_currentControl = m_inputControl;
}
- // 1.a) check target BHP
- GEOS_THROW_IF( m_targetBHP < 0,
- getWrapperDataContext( viewKeyStruct::targetBHPString() ) <<
- ": Target bottom-hole pressure is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetBHPString() ) );
-
- // 1.b) check target rates
- GEOS_THROW_IF( m_targetTotalRate < 0,
- getWrapperDataContext( viewKeyStruct::targetTotalRateString() ) << ": Target rate is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetTotalRateString() ) );
-
- GEOS_THROW_IF( m_targetPhaseRate < 0,
- getWrapperDataContext( viewKeyStruct::targetPhaseRateString() ) << ": Target oil rate is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetPhaseRateString() ) );
-
- GEOS_THROW_IF( m_targetMassRate < 0,
- getWrapperDataContext( viewKeyStruct::targetMassRateString() ) << ": Target mass rate is negative",
- InputError, getWrapperDataContext( viewKeyStruct::targetMassRateString() ) );
-
- GEOS_THROW_IF( (m_injectionStream.empty() && m_injectionTemperature >= 0) ||
- (!m_injectionStream.empty() && m_injectionTemperature < 0),
- "WellControls " << getDataContext() << ": Both "
- << viewKeyStruct::injectionStreamString() << " and " << viewKeyStruct::injectionTemperatureString()
- << " must be specified for multiphase simulations",
- InputError, getDataContext() );
-
- // 1.c) Set the multiplier for the rates
- if( isProducer() )
- {
- m_rateSign = -1.0;
- }
- else
- {
- m_rateSign = 1.0;
- }
-
- // 2) check injection stream
- if( !m_injectionStream.empty())
- {
- real64 sum = 0.0;
- for( localIndex ic = 0; ic < m_injectionStream.size(); ++ic )
- {
- GEOS_ERROR_IF( m_injectionStream[ic] < 0.0 || m_injectionStream[ic] > 1.0,
- getWrapperDataContext( viewKeyStruct::injectionStreamString() ) << ": Invalid injection stream",
- getWrapperDataContext( viewKeyStruct::injectionStreamString() ) );
- sum += m_injectionStream[ic];
- }
- GEOS_THROW_IF( LvArray::math::abs( 1.0 - sum ) > std::numeric_limits< real64 >::epsilon(),
- getWrapperDataContext( viewKeyStruct::injectionStreamString() ) << ": Invalid injection stream",
- InputError, getWrapperDataContext( viewKeyStruct::injectionStreamString() ) );
- }
// 3) check the flag for surface / reservoir conditions
GEOS_THROW_IF( m_useSurfaceConditions != 0 && m_useSurfaceConditions != 1,
getWrapperDataContext( viewKeyStruct::useSurfaceConditionsString() ) << ": The flag to select surface/reservoir conditions must be equal to 0 or 1",
InputError, getWrapperDataContext( viewKeyStruct::useSurfaceConditionsString() ) );
- // 4) check that at least one rate constraint has been defined
- GEOS_THROW_IF( ((m_targetPhaseRate <= 0.0 && m_targetPhaseRateTableName.empty()) &&
- (m_targetMassRate <= 0.0 && m_targetMassRateTableName.empty()) &&
- (m_targetTotalRate <= 0.0 && m_targetTotalRateTableName.empty())),
- "WellControls " << getDataContext() << ": You need to specify a phase, mass, or total rate constraint. \n" <<
- "The phase rate constraint can be specified using " <<
- "either " << viewKeyStruct::targetPhaseRateString() <<
- " or " << viewKeyStruct::targetPhaseRateTableNameString() << ".\n" <<
- "The total rate constraint can be specified using " <<
- "either " << viewKeyStruct::targetTotalRateString() <<
- " or " << viewKeyStruct::targetTotalRateTableNameString()<<
- "The mass rate constraint can be specified using " <<
- "either " << viewKeyStruct::targetMassRateString() <<
- " or " << viewKeyStruct::targetMassRateTableNameString(),
- InputError, getDataContext() );
-
- // 5) check whether redundant information has been provided
- GEOS_THROW_IF( ((m_targetPhaseRate > 0.0 && !m_targetPhaseRateTableName.empty())),
- "WellControls " << getDataContext() << ": You have provided redundant information for well phase rate." <<
- " The keywords " << viewKeyStruct::targetPhaseRateString() << " and " << viewKeyStruct::targetPhaseRateTableNameString() << " cannot be specified together",
- InputError, getDataContext() );
-
- GEOS_THROW_IF( ((m_targetTotalRate > 0.0 && !m_targetTotalRateTableName.empty())),
- "WellControls " << getDataContext() << ": You have provided redundant information for well total rate." <<
- " The keywords " << viewKeyStruct::targetTotalRateString() << " and " << viewKeyStruct::targetTotalRateTableNameString() << " cannot be specified together",
- InputError, getDataContext() );
-
- GEOS_THROW_IF( ((m_targetBHP > 0.0 && !m_targetBHPTableName.empty())),
- "WellControls " << getDataContext() << ": You have provided redundant information for well BHP." <<
- " The keywords " << viewKeyStruct::targetBHPString() << " and " << viewKeyStruct::targetBHPTableNameString() << " cannot be specified together",
- InputError, getDataContext() );
+ // tjb add more constraint validation
+ // 1) liquid rate - phase names consistent with fluild model
+ // 2) at least one bhp and one rate constraint defined
+ // 3) constraint type and well type compatibility
- GEOS_THROW_IF( ((m_targetMassRate > 0.0 && !m_targetMassRateTableName.empty())),
- "WellControls " << getDataContext() << ": You have provided redundant information for well mass rate." <<
- " The keywords " << viewKeyStruct::targetMassRateString() << " and " << viewKeyStruct::targetMassRateTableNameString() << " cannot be specified together",
- InputError, getDataContext() );
+ //GEOS_THROW_IF( ((m_targetMassRate > 0.0 && m_useSurfaceConditions==0)),
+ // "WellControls " << getDataContext() << ": Option only valid if useSurfaceConditions set to 1",
+ // InputError );
- GEOS_THROW_IF( ((m_targetMassRate > 0.0 && m_useSurfaceConditions==0)),
- "WellControls " << getDataContext() << ": Option only valid if useSurfaceConditions set to 1",
- InputError, getDataContext() );
- // 6.1) If the well is under BHP control then the BHP must be specified.
- // Otherwise the BHP will be set to a default value.
- if( m_currentControl == Control::BHP )
- {
- GEOS_THROW_IF( ((m_targetBHP <= 0.0 && m_targetBHPTableName.empty())),
- "WellControls " << getDataContext() << ": You have to provide well BHP by specifying either "
- << viewKeyStruct::targetBHPString() << " or " << viewKeyStruct::targetBHPTableNameString(),
- InputError, getDataContext() );
- }
- else if( m_targetBHP <= 0.0 && m_targetBHPTableName.empty() )
- {
- m_targetBHP = isProducer() ? WellConstants::defaultProducerBHP : WellConstants::defaultInjectorBHP;
- GEOS_LOG_LEVEL_RANK_0( logInfo::WellControl,
- GEOS_FMT( "WellControls {}: Setting {} to default value {}", getDataContext(), viewKeyStruct::targetBHPString(), m_targetBHP ));
- }
+ // 8) Make sure that the initial pressure coefficient is positive
+ GEOS_THROW_IF( m_initialPressureCoefficient < 0,
+ getWrapperDataContext( viewKeyStruct::initialPressureCoefficientString() ) <<
+ ": This tuning coefficient is negative",
+ InputError );
// 6.2) Check incoherent information
@@ -377,79 +260,6 @@ void WellControls::postInputInitialization()
<< EnumStrings< Control >::toString( Control::MASSRATE ),
InputError, getDataContext() );
- // 8) Make sure that the initial pressure coefficient is positive
- GEOS_THROW_IF( m_initialPressureCoefficient < 0,
- getWrapperDataContext( viewKeyStruct::initialPressureCoefficientString() ) <<
- ": This tuning coefficient is negative",
- InputError, getWrapperDataContext( viewKeyStruct::initialPressureCoefficientString() ) );
-
-
- // 9) Create time-dependent BHP table
- if( m_targetBHPTableName.empty() )
- {
- m_targetBHPTableName = getName()+"_ConstantBHP_table";
- m_targetBHPTable = createWellTable( m_targetBHPTableName, m_targetBHP );
- }
- else
- {
- FunctionManager & functionManager = FunctionManager::getInstance();
- m_targetBHPTable = &(functionManager.getGroup< TableFunction const >( m_targetBHPTableName ));
-
- GEOS_THROW_IF( m_targetBHPTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower,
- "WellControls " << getDataContext() << ": The interpolation method for the time-dependent BHP table "
- << m_targetBHPTable->getName() << " should be TableFunction::InterpolationType::Lower",
- InputError, getDataContext() );
- }
-
- // 10) Create time-dependent total rate table
- if( m_targetTotalRateTableName.empty() )
- {
- m_targetTotalRateTableName = getName()+"_ConstantTotalRate_table";
- m_targetTotalRateTable = createWellTable( m_targetTotalRateTableName, m_targetTotalRate );
- }
- else
- {
- FunctionManager & functionManager = FunctionManager::getInstance();
- m_targetTotalRateTable = &(functionManager.getGroup< TableFunction const >( m_targetTotalRateTableName ));
-
- GEOS_THROW_IF( m_targetTotalRateTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower,
- "WellControls " << getDataContext() << ": The interpolation method for the time-dependent total rate table "
- << m_targetTotalRateTable->getName() << " should be TableFunction::InterpolationType::Lower",
- InputError, getDataContext() );
- }
-
- // 11) Create time-dependent phase rate table
- if( m_targetPhaseRateTableName.empty() )
- {
- m_targetPhaseRateTableName = getName()+"_ConstantPhaseRate_table";
- m_targetPhaseRateTable = createWellTable( m_targetPhaseRateTableName, m_targetPhaseRate );
- }
- else
- {
- FunctionManager & functionManager = FunctionManager::getInstance();
- m_targetPhaseRateTable = &(functionManager.getGroup< TableFunction const >( m_targetPhaseRateTableName ));
-
- GEOS_THROW_IF( m_targetPhaseRateTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower,
- "WellControls " << getDataContext() << ": The interpolation method for the time-dependent phase rate table "
- << m_targetPhaseRateTable->getName() << " should be TableFunction::InterpolationType::Lower",
- InputError, getDataContext() );
- }
- // Create time-dependent mass rate table
- if( m_targetMassRateTableName.empty() )
- {
- m_targetMassRateTableName = getName()+"_ConstantMassRate_table";
- m_targetMassRateTable = createWellTable( m_targetMassRateTableName, m_targetMassRate );
- }
- else
- {
- FunctionManager & functionManager = FunctionManager::getInstance();
- m_targetMassRateTable = &(functionManager.getGroup< TableFunction const >( m_targetMassRateTableName ));
-
- GEOS_THROW_IF( m_targetMassRateTable->getInterpolationMethod() != TableFunction::InterpolationType::Lower,
- "WellControls " << getDataContext() << ": The interpolation method for the time-dependent mass rate table "
- << m_targetMassRateTable->getName() << " should be TableFunction::InterpolationType::Lower",
- InputError, getDataContext() );
- }
// 12) Create the time-dependent well status table
if( m_statusTableName.empty())
{
@@ -480,12 +290,31 @@ void WellControls::setWellStatus( real64 const & currentTime, WellControls::Stat
m_wellStatus = status;
if( m_wellStatus == WellControls::Status::OPEN )
{
-
- if( isZero( getTargetTotalRate( currentTime ) ) && isZero( getTargetPhaseRate( currentTime ) )
- && isZero( getTargetMassRate( currentTime ) ) )
+ if( isProducer())
{
- m_wellStatus = WellControls::Status::CLOSED;
+ std::vector< WellConstraintBase * > const constraints = getProdRateConstraints();
+ for( auto const & constraint : constraints )
+ {
+ if( isZero( constraint->getConstraintValue( currentTime ) ) )
+ {
+ m_wellStatus = WellControls::Status::CLOSED;
+ break;
+ }
+ }
+ }
+ else
+ {
+ std::vector< WellConstraintBase * > const constraints = getInjRateConstraints();
+ for( auto const & constraint : constraints )
+ {
+ if( isZero( constraint->getConstraintValue( currentTime ) ) )
+ {
+ m_wellStatus = WellControls::Status::CLOSED;
+ break;
+ }
+ }
}
+
if( m_statusTable->evaluate( ¤tTime ) < LvArray::NumericLimits< real64 >::epsilon )
{
m_wellStatus = WellControls::Status::CLOSED;
@@ -498,13 +327,46 @@ bool WellControls::isWellOpen() const
return getWellStatus() == WellControls::Status::OPEN;
}
+void WellControls::setWellState( bool open )
+{
+ m_wellOpen = open;
+}
+
+bool WellControls::getWellState() const
+{
+ return m_wellOpen;
+}
+
+void WellControls::setConstraintSwitch( bool constraintSwitch )
+{
+ m_constraintSwitch = constraintSwitch;
+}
+
+bool WellControls::getConstraintSwitch() const
+{
+ return m_constraintSwitch;
+}
+
void WellControls::setNextDtFromTables( real64 const & currentTime, real64 & nextDt )
{
- WellControls::setNextDtFromTable( m_targetBHPTable, currentTime, nextDt );
- WellControls::setNextDtFromTable( m_targetMassRateTable, currentTime, nextDt );
- WellControls::setNextDtFromTable( m_targetPhaseRateTable, currentTime, nextDt );
- WellControls::setNextDtFromTable( m_targetTotalRateTable, currentTime, nextDt );
+ if( isProducer() )
+ {
+ getMinBHPConstraint()->setNextDtFromTables( currentTime, nextDt );
+ for( auto const & constraint : m_productionRateConstraintList )
+ {
+ constraint->setNextDtFromTables( currentTime, nextDt );
+ }
+ }
+ else
+ {
+ getMaxBHPConstraint()->setNextDtFromTables( currentTime, nextDt );
+ for( auto const & constraint : m_injectionRateConstraintList )
+ {
+ constraint->setNextDtFromTables( currentTime, nextDt );
+ }
+ }
+
WellControls::setNextDtFromTable( m_statusTable, currentTime, nextDt );
}
@@ -522,4 +384,80 @@ void WellControls::setNextDtFromTable( TableFunction const * table, real64 const
}
}
+real64 WellControls::getTargetBHP( real64 const & targetTime ) const
+{
+ if( isProducer())
+ {
+ return m_minBHPConstraint->getConstraintValue( targetTime );
+ }
+ return m_maxBHPConstraint->getConstraintValue( targetTime );
+}
+
+
+real64 WellControls::getInjectionTemperature() const
+{
+ real64 injectionTemperature = 0.0;
+ this->forInjectionConstraints< InjectionConstraint< PhaseVolumeRateConstraint >, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint > >( [&] ( auto & constraint )
+ {
+ if( constraint.isConstraintActive())
+ {
+ injectionTemperature = constraint.getInjectionTemperature();
+ return;
+ }
+ } );
+ return injectionTemperature;
+}
+
+
+arrayView1d< real64 const > WellControls::getInjectionStream() const
+{
+ arrayView1d< real64 const > injectionStream;
+ forInjectionConstraints< InjectionConstraint< PhaseVolumeRateConstraint >, InjectionConstraint< VolumeRateConstraint >, InjectionConstraint< MassRateConstraint > >( [&] ( auto & constraint )
+ {
+ if( constraint.isConstraintActive() )
+ {
+ injectionStream = constraint.getInjectionStream();
+ return;
+ }
+ } );
+
+ return injectionStream;
+}
+
+integer WellControls::getConstraintPhaseIndex() const
+{
+ integer phaseIndex = -1;
+
+ if( isProducer() )
+ {
+ forProductionConstraints< ProductionConstraint< PhaseVolumeRateConstraint > >( [&] ( auto & constraint )
+ {
+ if( constraint.isConstraintActive() )
+ {
+ phaseIndex = constraint.getPhaseIndex();
+ }
+ } );
+ }
+ else
+ {
+ forInjectionConstraints< InjectionConstraint< PhaseVolumeRateConstraint > >( [&] ( auto & constraint )
+ {
+ if( constraint.isConstraintActive() )
+ {
+ phaseIndex = constraint.getPhaseIndex();
+ }
+ } );
+ }
+
+ return phaseIndex;
+}
+
+real64 WellControls::getReferenceElevation() const
+{
+ if( isProducer () )
+ {
+ return getMinBHPConstraint()->getReferenceElevation();
+ }
+ return getMaxBHPConstraint()->getReferenceElevation();
+}
} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp
index 301c3c42f7c..625891c00ff 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp
@@ -26,6 +26,15 @@
#include "functions/TableFunction.hpp"
#include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellInjectionConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellProductionConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp"
+#include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
+#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
namespace geos
{
namespace dataRepository
@@ -124,33 +133,127 @@ class WellControls : public dataRepository::Group
///@}
/**
- * @name Getters / Setters
+ * @brief Create a new geometric object (box, plane, etc) as a child of this group.
+ * @param childKey the catalog key of the new geometric object to create
+ * @param childName the name of the new geometric object in the repository
+ * @return the group child
*/
- ///@{
+ virtual Group * createChild( string const & childKey, string const & childName ) override;
+ /// Expand catalog for schema generation
+
+ virtual void expandObjectCatalogs() override;
/**
- * @brief Set the control type to BHP and set a numerical value for the control.
- * @param[in] val value for the BHP control
+ * @brief Apply a given functor to a container if the container can be
+ * cast to one of the specified types.
+ * @tparam CASTTYPE the first type that will be used in the attempted casting of container
+ * @tparam CASTTYPES a variadic list of types that will be used in the attempted casting of container
+ * @tparam CONTAINERTYPE the type of container
+ * @tparam LAMBDA the type of lambda function to call in the function
+ * @param[in] container a pointer to the container which will be passed to the lambda function
+ * @param[in] lambda the lambda function to call in the function
+ * @return a boolean to indicate whether the lambda was successfully applied to the container.
*/
- void switchToBHPControl( real64 const & val );
+ template< typename T0, typename T1, typename ... CASTTYPES, typename CONTAINERTYPE, typename LAMBDA >
+ static bool applyLambdaToContainer( CONTAINERTYPE container, LAMBDA && lambda )
+ {
+ using Pointee = std::remove_pointer_t< std::remove_reference_t< CONTAINERTYPE > >;
+ using T = std::conditional_t< std::is_const< Pointee >::value, T0 const, T0 >;
+ T * const castedContainer = dynamic_cast< T * >( container );
+
+ if( castedContainer != nullptr )
+ {
+ lambda( *castedContainer );
+ return true;
+ }
+
+ return applyLambdaToContainer< T1, CASTTYPES... >( container, std::forward< LAMBDA >( lambda ) );
+ }
+
+ // Base case: no more types to try
+ template< typename CONTAINERTYPE, typename LAMBDA >
+ static bool applyLambdaToContainer( CONTAINERTYPE /*container*/, LAMBDA && /*lambda*/ )
+ {
+ return false;
+ }
+
+ // Single-type overload: try only T0 and stop
+ template< typename T0, typename CONTAINERTYPE, typename LAMBDA >
+ static bool applyLambdaToContainer( CONTAINERTYPE container, LAMBDA && lambda )
+ {
+ using Pointee = std::remove_pointer_t< std::remove_reference_t< CONTAINERTYPE > >;
+ using T = std::conditional_t< std::is_const< Pointee >::value, T0 const, T0 >;
+ T * const castedContainer = dynamic_cast< T * >( container );
+
+ if( castedContainer != nullptr )
+ {
+ lambda( *castedContainer );
+ return true;
+ }
+
+ return false;
+ }
+
/**
- * @brief Set the control type to total rate and set a numerical value for the control.
- * @param[in] val value for the total volumetric rate
+ * @copydoc forInjectionConstraints(LAMBDA &&)
*/
- void switchToTotalRateControl( real64 const & val );
+ template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
+ void forInjectionConstraints( LAMBDA && lambda ) const
+ {
+ for( auto const * constraintIter : m_injectionRateConstraintList )
+ {
+ applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto const & castedSubGroup )
+ {
+ lambda( castedSubGroup );
+ } );
+ }
+ }
+ // non-const overload
+ template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
+ void forInjectionConstraints( LAMBDA && lambda )
+ {
+ for( auto * constraintIter : m_injectionRateConstraintList )
+ {
+ applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto & castedSubGroup )
+ {
+ lambda( castedSubGroup );
+ } );
+ }
+ }
/**
- * @brief Set the control type to mass rate and set a numerical value for the control.
- * @param[in] val value for the mass rate
+ * @copydoc forProductionConstraints(LAMBDA &&)
*/
- void switchToMassRateControl( real64 const & val );
+ template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
+ void forProductionConstraints( LAMBDA && lambda ) const
+ {
+ for( auto const * constraintIter : m_productionRateConstraintList )
+ {
+ applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto const & castedSubGroup )
+ {
+ lambda( castedSubGroup );
+ } );
+ }
+ }
+ // non-const overload
+ template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
+ void forProductionConstraints( LAMBDA && lambda )
+ {
+ for( auto * constraintIter : m_productionRateConstraintList )
+ {
+ applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto & castedSubGroup )
+ {
+ lambda( castedSubGroup );
+ } );
+ }
+ }
/**
- * @brief Set the control type to phase rate and set a numerical value for the control.
- * @param[in] val value for the phase volumetric rate
+ * @name Getters / Setters
*/
- void switchToPhaseRateControl( real64 const & val );
+ ///@{
+
/**
* @brief Get the control type for the well.
@@ -170,11 +273,6 @@ class WellControls : public dataRepository::Group
*/
Control getInputControl() const { return m_inputControl; }
- /**
- * @brief Getter for the reference elevation where the BHP control is enforced
- * @return the reference elevation
- */
- real64 getReferenceElevation() const { return m_refElevation; }
/**
* @brief Getter for the reference gravity coefficient
@@ -189,58 +287,38 @@ class WellControls : public dataRepository::Group
/**
- * @brief Get the target bottom hole pressure value.
- * @return a value for the target bottom hole pressure
+ * @brief Returns the target bottom hole pressure value.
+ * @param[in] targetTime time at which to evaluate the constraint
+ * @return the injector maximum bottom hole pressure or producer minimum bottom hole pressure
*/
- real64 getTargetBHP( real64 const & currentTime ) const
- {
- return m_targetBHPTable->evaluate( ¤tTime );
- }
+ real64 getTargetBHP( real64 const & targetTime ) const;
- /**
- * @brief Get the target total rate
- * @return the target total rate
- */
- real64 getTargetTotalRate( real64 const & currentTime ) const
- {
- return m_rateSign * m_targetTotalRateTable->evaluate( ¤tTime );
- }
/**
- * @brief Get the target phase rate
- * @return the target phase rate
+ * @brief Const accessor for the temperature of the injection stream
+ * @return the temperature of the injection stream
*/
- real64 getTargetPhaseRate( real64 const & currentTime ) const
- {
- return m_rateSign * m_targetPhaseRateTable->evaluate( ¤tTime );
- }
+ real64 getInjectionTemperature() const;
/**
- * @brief Get the target mass rate
- * @return the target mass rate
+ * @brief Const accessor for the injection stream
+ * @return the injection stream
*/
- real64 getTargetMassRate( real64 const & currentTime ) const
- {
- return m_rateSign * m_targetMassRateTable->evaluate( ¤tTime );
- }
+ arrayView1d< real64 const > getInjectionStream() const;
- /**
- * @brief Get the target phase name
- * @return the target phase name
- */
- const string & getTargetPhaseName() const { return m_targetPhaseName; }
/**
- * @brief Const accessor for the composition of the injection stream
- * @return a global component fraction vector
+ * @brief Const accessor for the phase constraint index
+ * @return phase index associated with phase constraint
*/
- arrayView1d< real64 const > getInjectionStream() const { return m_injectionStream; }
+ integer getConstraintPhaseIndex() const;
/**
- * @brief Const accessor for the temperature of the injection stream
- * @return the temperature of the injection stream
+ * @brief Return the reference elvation where pressure constraint is measured
+ * @return vertical location of constraint
*/
- real64 getInjectionTemperature() const { return m_injectionTemperature; }
+ real64 getReferenceElevation() const;
+
/**
* @brief Getter for the flag specifying whether we check rates at surface or reservoir conditions
@@ -284,6 +362,18 @@ class WellControls : public dataRepository::Group
*/
bool isWellOpen() const;
+ void setWellState( bool open );
+ bool getWellState() const;
+
+
+ void setConstraintSwitch( bool constraintSwitch );
+ bool getConstraintSwitch() const;
+
+ void setCurrentConstraint( WellConstraintBase * currentConstraint ) { m_currentConstraint = currentConstraint;}
+ WellConstraintBase * getCurrentConstraint() { return m_currentConstraint; }
+ WellConstraintBase const * getCurrentConstraint() const { return m_currentConstraint; }
+
+
/**
* @brief Getter for the flag to enable crossflow
* @return the flag deciding whether crossflow is allowed or not
@@ -303,6 +393,7 @@ class WellControls : public dataRepository::Group
*/
void setNextDtFromTables( real64 const & currentTime, real64 & nextDt );
+
/**
* @brief setter for multi fluid separator
* @param[in] fluidSeparatorPtr single or multiphase separator
@@ -314,6 +405,13 @@ class WellControls : public dataRepository::Group
*/
constitutive::MultiFluidBase & getMultiFluidSeparator() { return dynamicCast< constitutive::MultiFluidBase & >( *m_fluidSeparatorPtr ); }
+ /**
+ * @brief Getter for single fluid separator
+ * @return reference to separator
+ */
+ constitutive::SingleFluidBase & getSingleFluidSeparator() { return dynamicCast< constitutive::SingleFluidBase & >( *m_fluidSeparatorPtr ); }
+
+
/**
* @brief Getter for the reservoir average pressure when m_useSurfaceConditions == 0
* @return the pressure
@@ -352,6 +450,7 @@ class WellControls : public dataRepository::Group
WellControls::Status getWellStatus () const { return m_wellStatus; }
///@}
+
/**
* @brief Struct to serve as a container for variable strings and keys.
* @struct viewKeyStruct
@@ -362,24 +461,10 @@ class WellControls : public dataRepository::Group
static constexpr char const * refElevString() { return "referenceElevation"; }
/// String key for the well type
static constexpr char const * typeString() { return "type"; }
- /// String key for the well input control
- static constexpr char const * inputControlString() { return "control"; }
/// String key for the well current control
static constexpr char const * currentControlString() { return "currentControl"; }
- /// String key for the well target BHP
- static constexpr char const * targetBHPString() { return "targetBHP"; }
- /// String key for the well target rate
- static constexpr char const * targetTotalRateString() { return "targetTotalRate"; }
- /// String key for the well target phase rate
- static constexpr char const * targetPhaseRateString() { return "targetPhaseRate"; }
- /// String key for the well target phase name
- static constexpr char const * targetPhaseNameString() { return "targetPhaseName"; }
- /// String key for the well target phase name
- static constexpr char const * targetMassRateString() { return "targetMassRate"; }
- /// String key for the well injection stream
- static constexpr char const * injectionStreamString() { return "injectionStream"; }
- /// String key for the well injection temperature
- static constexpr char const * injectionTemperatureString() { return "injectionTemperature"; }
+ /// String key for the well input control
+ static constexpr char const * inputControlString() { return "control"; }
/// String key for checking the rates at surface conditions
static constexpr char const * useSurfaceConditionsString() { return "useSurfaceConditions"; }
/// String key for reference reservoir region
@@ -388,14 +473,7 @@ class WellControls : public dataRepository::Group
static constexpr char const * surfacePressureString() { return "surfacePressure"; }
/// String key for the surface temperature
static constexpr char const * surfaceTemperatureString() { return "surfaceTemperature"; }
- /// string key for total rate table name
- static constexpr char const * targetTotalRateTableNameString() { return "targetTotalRateTableName"; }
- /// string key for phase rate table name
- static constexpr char const * targetPhaseRateTableNameString() { return "targetPhaseRateTableName"; }
- /// string key for mass rate table name
- static constexpr char const * targetMassRateTableNameString() { return "targetMassRateTableName"; }
- /// string key for BHP table name
- static constexpr char const * targetBHPTableNameString() { return "targetBHPTableName"; }
+
/// string key for status table name
static constexpr char const * statusTableNameString() { return "statusTableName"; }
/// string key for perforation status table name
@@ -404,13 +482,53 @@ class WellControls : public dataRepository::Group
static constexpr char const * enableCrossflowString() { return "enableCrossflow"; }
/// string key for the initial pressure coefficient
static constexpr char const * initialPressureCoefficientString() { return "initialPressureCoefficient"; }
-
+ /// string key for the esitmate well solution flag
+ static constexpr char const * estimateWellSolutionString() { return "estimateWellSolution"; }
+
+ /// string key for the minimum BHP presssure for a producer
+ static constexpr char const * minimumBHPConstraintString() { return "MinimumBHPConstraint"; }
+ /// string key for the maximum BHP presssure for a injection
+ static constexpr char const * maximumBHPConstraintString() { return "MaximumBHPConstraint"; }
+ /// string key for the maximum phase rate for a producer
+ static constexpr char const * productionPhaseVolumeRateConstraintString() { return "ProductionPhaseVolumeRateConstraint"; }
+ /// string key for the maximum phase rate for a injection
+ static constexpr char const * injectionPhaseVolumeRateConstraint() { return "InjectionPhaseVolumeRateConstraint"; }
+ /// string key for the maximum volume rate for a producer
+ static constexpr char const * productionVolumeRateConstraint() { return "ProductionVolumeRateConstraint"; }
+ /// string key for the maximum volume rate for a injector
+ static constexpr char const * injectionVolumeRateConstraint() { return "InjectionVolumeRateConstraint"; }
+ /// string key for the maximum mass rate for a producer
+ static constexpr char const * productionMassRateConstraint() { return "ProductionMassRateConstraint"; }
+ /// string key for the maximum mass rate for a injector
+ static constexpr char const * injectionMassRateConstraint() { return "InjectionMassRateConstraint"; }
+ /// string key for the liquid rate for a producer
+ static constexpr char const * productionLiquidRateConstraint() { return "ProductionLiquidRateConstraint"; }
}
/// ViewKey struct for the WellControls class
viewKeysWellControls;
static void setNextDtFromTable( TableFunction const * table, real64 const currentTime, real64 & nextDt );
+ /**
+ * @brief Create a constraint
+ * @tparam ConstraintType the type of constraint to create
+ * @param[in] constraintName name to assign to the constraint
+ */
+ template< typename ConstraintType > void createConstraint ( string const & constraintName );
+
+
+ /**
+ * @brief Getters for constraints
+ */
+ MinimumBHPConstraint * getMinBHPConstraint() { return m_minBHPConstraint; };
+ MinimumBHPConstraint * getMinBHPConstraint() const { return m_minBHPConstraint; };
+ MaximumBHPConstraint * getMaxBHPConstraint() { return m_maxBHPConstraint; };
+ MaximumBHPConstraint * getMaxBHPConstraint() const { return m_maxBHPConstraint; };
+ // Lists of rate constraints
+ std::vector< WellConstraintBase * > getProdRateConstraints() { return m_productionRateConstraintList; };
+ std::vector< WellConstraintBase * > getProdRateConstraints() const { return m_productionRateConstraintList; };
+ std::vector< WellConstraintBase * > getInjRateConstraints() { return m_injectionRateConstraintList; }
+ std::vector< WellConstraintBase * > getInjRateConstraints() const { return m_injectionRateConstraintList; }
protected:
virtual void postInputInitialization() override;
@@ -434,27 +552,6 @@ class WellControls : public dataRepository::Group
/// Well controls as a Control enum
Control m_currentControl;
- /// Target bottom hole pressure value
- real64 m_targetBHP;
-
- /// Target rate value
- real64 m_targetTotalRate;
-
- /// Target phase rate value
- real64 m_targetPhaseRate;
-
- /// Name of the targeted phase
- string m_targetPhaseName;
-
- /// Target MassRate
- real64 m_targetMassRate;
-
- /// Vector with global component fractions at the injector
- array1d< real64 > m_injectionStream;
-
- /// Temperature at the injector
- real64 m_injectionTemperature;
-
/// Flag to decide whether rates are controlled at rates or surface conditions
integer m_useSurfaceConditions;
@@ -470,17 +567,6 @@ class WellControls : public dataRepository::Group
/// Surface temperature
real64 m_surfaceTemp;
- /// Total rate table name
- string m_targetTotalRateTableName;
-
- /// Phase rate table name
- string m_targetPhaseRateTableName;
-
- /// Mass rate table name
- string m_targetMassRateTableName;
-
- /// BHP table name
- string m_targetBHPTableName;
/// Well status table name
string m_statusTableName;
@@ -497,25 +583,33 @@ class WellControls : public dataRepository::Group
/// Rate sign. +1 for injector, -1 for producer
real64 m_rateSign;
- /// Total rate table
- TableFunction const * m_targetTotalRateTable;
- /// Phase rate table
- TableFunction const * m_targetPhaseRateTable;
+ /// Status table
+ TableFunction const * m_statusTable;
+
+ bool m_wellOpen;
- /// Mass rate table
- TableFunction const * m_targetMassRateTable;
- /// BHP table
- TableFunction const * m_targetBHPTable;
- /// Status table
- TableFunction const * m_statusTable;
+ /// List of constraints
+ //constraint_array m_ConstraintList;
+ // Bool to trigger old/new constraint switch logic
+ bool m_constraintSwitch;
+
+ // Current constraint
+ WellConstraintBase * m_currentConstraint;
+ // Minimum and maximum BHP and WHP constraints
+ MinimumBHPConstraint * m_minBHPConstraint;
+ MaximumBHPConstraint * m_maxBHPConstraint;
+
+
+ // Lists of rate constraints
+ std::vector< WellConstraintBase * > m_productionRateConstraintList;
+ std::vector< WellConstraintBase * > m_injectionRateConstraintList;
/// Well status
WellControls::Status m_wellStatus;
-
/// Region average pressure used in volume rate constraint calculations
real64 m_regionAveragePressure;
@@ -524,11 +618,15 @@ class WellControls : public dataRepository::Group
};
-ENUM_STRINGS( WellControls::Type,
+
+// Use local aliases to avoid accidental macro expansion of the tokens 'Type' or 'Control'
+using WellControls_Type = WellControls::Type;
+ENUM_STRINGS( WellControls_Type,
"producer",
"injector" );
-ENUM_STRINGS( WellControls::Control,
+using WellControls_Control = WellControls::Control;
+ENUM_STRINGS( WellControls_Control,
"BHP",
"phaseVolRate",
"totalVolRate",
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellInjectionConstraint.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellInjectionConstraint.cpp
new file mode 100644
index 00000000000..57145a752dc
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellInjectionConstraint.cpp
@@ -0,0 +1,108 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellInjectionConstraint.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellInjectionConstraint.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+#include "WellLiquidRateConstraint.hpp"
+#include "WellMassRateConstraint.hpp"
+#include "WellPhaseVolumeRateConstraint.hpp"
+#include "WellVolumeRateConstraint.hpp"
+
+namespace geos
+{
+using namespace dataRepository;
+
+template< typename ConstraintRateType >
+InjectionConstraint< ConstraintRateType >::InjectionConstraint( string const & name, Group * const parent )
+ : ConstraintRateType( name, parent )
+{
+ // set rate sign for injectors (base class member)
+ this->m_rateSign = 1.0;
+ classtype::registerWrapper( injectionStreamKey::injectionStreamString(), &m_injectionStream ).
+ setDefaultValue( -1 ).
+ setSizedFromParent( 0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Global component densities of the injection stream [moles/m^3 or kg/m^3]" );
+
+ InjectionConstraint< ConstraintRateType >::registerWrapper( injectionStreamKey::injectionTemperatureString(), &m_injectionTemperature ).
+ setDefaultValue( -1 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Temperature of the injection stream [K]" );
+}
+template< typename ConstraintRateType >
+InjectionConstraint< ConstraintRateType >::~InjectionConstraint()
+{}
+template< typename ConstraintRateType >
+void InjectionConstraint< ConstraintRateType >::postInputInitialization()
+{
+ // Validate value and table options
+ ConstraintRateType::postInputInitialization();
+
+// Validate the injection stream and temperature
+ validateInjectionStream( );
+
+}
+template< typename ConstraintRateType >
+void InjectionConstraint< ConstraintRateType >::validateInjectionStream( )
+{
+ GEOS_THROW_IF( (m_injectionStream.empty() && m_injectionTemperature >= 0) ||
+ (!m_injectionStream.empty() && m_injectionTemperature < 0),
+ this->getName() << " " << this->getDataContext() << ": Both "
+ << injectionStreamKey::injectionStreamString() << " and " << injectionStreamKey::injectionTemperatureString()
+ << " must be specified for multiphase simulations",
+ InputError );
+
+ if( !m_injectionStream.empty())
+ {
+ real64 sum = 0.0;
+ for( localIndex ic = 0; ic < m_injectionStream.size(); ++ic )
+ {
+ GEOS_ERROR_IF( m_injectionStream[ic] < 0.0 || m_injectionStream[ic] > 1.0,
+ classtype::getWrapperDataContext( injectionStreamKey::injectionStreamString() ) << ": Invalid injection stream" );
+ sum += m_injectionStream[ic];
+ }
+ GEOS_THROW_IF( LvArray::math::abs( 1.0 - sum ) > std::numeric_limits< real64 >::epsilon(),
+ classtype::getWrapperDataContext( injectionStreamKey::injectionStreamString() ) << ": Invalid injection stream",
+ InputError );
+ }
+}
+
+// Register concrete wrapper constraint types and instantiate templates.
+template class InjectionConstraint< LiquidRateConstraint >;
+using InjectionLiquidRateConstraint = InjectionConstraint< LiquidRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, InjectionLiquidRateConstraint, string const &, Group * const )
+
+template class InjectionConstraint< MassRateConstraint >;
+using InjectionMassRateConstraint = InjectionConstraint< MassRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, InjectionMassRateConstraint, string const &, Group * const )
+
+template class InjectionConstraint< PhaseVolumeRateConstraint >;
+using InjectionPhaseVolumeRateConstraint = InjectionConstraint< PhaseVolumeRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, InjectionPhaseVolumeRateConstraint, string const &, Group * const )
+
+template class InjectionConstraint< VolumeRateConstraint >;
+using InjectionVolumeRateConstraint = InjectionConstraint< VolumeRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, InjectionVolumeRateConstraint, string const &, Group * const )
+
+
+}
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellInjectionConstraint.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellInjectionConstraint.hpp
new file mode 100644
index 00000000000..1707f5f20e7
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellInjectionConstraint.hpp
@@ -0,0 +1,139 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellInjectionConstraint.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLINJECTIONCONSTRAINT_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLINJECTIONCONSTRAINT_HPP
+
+#include "common/format/EnumStrings.hpp"
+#include "dataRepository/Group.hpp"
+#include "functions/TableFunction.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+/**
+ * @class InjectionConstraint
+ * @brief This class describes constraint used to control a injection well.
+ */
+
+template< typename ConstraintType >
+class InjectionConstraint : public ConstraintType
+{
+public:
+ typedef InjectionConstraint< ConstraintType > classtype;
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit InjectionConstraint( string const & name, dataRepository::Group * const parent );
+
+ /**
+ * @brief Default destructor.
+ */
+ ~InjectionConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ InjectionConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ InjectionConstraint( InjectionConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ InjectionConstraint( InjectionConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ InjectionConstraint & operator=( InjectionConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ InjectionConstraint & operator=( InjectionConstraint && ) = delete;
+
+ ///@}
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "Injection"+ConstraintType::catalogName();
+ }
+
+ virtual string getCatalogName() const override { return catalogName(); }
+
+ struct injectionStreamKey
+ {
+ /// String key for the well injection stream
+ static constexpr char const * injectionStreamString() { return "injectionStream"; }
+ /// String key for the well injection temperature
+ static constexpr char const * injectionTemperatureString() { return "injectionTemperature"; }
+ };
+
+ /**
+ * @brief Const accessor for the composition of the injection stream
+ * @return a global component fraction vector
+ */
+ arrayView1d< real64 const > getInjectionStream() const { return m_injectionStream; }
+
+ /**
+ * @brief Const accessor for the temperature of the injection stream
+ * @return the temperature of the injection stream
+ */
+ real64 getInjectionTemperature() const { return m_injectionTemperature; }
+
+protected:
+
+ virtual void postInputInitialization() override;
+ static bool isViolated( const real64 & currentValue, const real64 & constraintValue )
+ { return currentValue > constraintValue; }
+
+ void validateInjectionStream();
+private:
+
+ /// Vector with global component fractions at the injector
+ array1d< real64 > m_injectionStream;
+
+ /// Temperature at the injector
+ real64 m_injectionTemperature;
+
+};
+
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLINJECTIONCONSTRAINT_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.cpp
new file mode 100644
index 00000000000..54424d9224e
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.cpp
@@ -0,0 +1,85 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellLiquidRateConstraint.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellLiquidRateConstraint.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+
+LiquidRateConstraint::LiquidRateConstraint( string const & name, Group * const parent )
+ : WellConstraintBase( name, parent )
+{
+ this->registerWrapper( viewKeyStruct::liquidRateString(), &this->m_constraintValue ).
+ setDefaultValue( 0.0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::WRITE_AND_READ ).
+ setDescription( "Phase rate, (if useSurfaceCondSitions: [surface m^3/s]; else [reservoir m^3/s]) " );
+
+ this->registerWrapper( viewKeyStruct::phaseNamesString(), &m_phaseNames ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ).
+ setInputFlag( InputFlags::REQUIRED ).
+ setDescription( "List of fluid phase names defining the liquid" );
+}
+
+LiquidRateConstraint::~LiquidRateConstraint()
+{}
+
+void LiquidRateConstraint::postInputInitialization()
+{
+ // Validate table options
+ WellConstraintBase::postInputInitialization();
+
+ // check constraint value
+ GEOS_THROW_IF( m_constraintValue < 0,
+ getWrapperDataContext( viewKeyStruct::liquidRateString() ) << ": Target value is negative",
+ InputError );
+
+ GEOS_THROW_IF ((m_constraintValue <= 0.0 && m_constraintScheduleTableName.empty()),
+ getName() << " " << getDataContext() << ": You need to specify a liquid rate constraint. \n" <<
+ "The rate constraint can be specified using " <<
+ "either " << viewKeyStruct::liquidRateString() <<
+ " or " << WellConstraintBase::viewKeyStruct::constraintScheduleTableNameString(),
+ InputError );
+}
+
+
+bool LiquidRateConstraint::checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const
+{
+ real64 const currentValue = currentConstraint.liquidRate();
+ real64 const constraintValue = this->getConstraintValue( currentTime );
+ if( this->m_rateSign < 0.0 )
+ {
+ // production: violated when current < constraint
+ return currentValue < constraintValue;
+ }
+ else
+ {
+ // injection: violated when current > constraint
+ return currentValue > constraintValue;
+ }
+}
+
+} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp
new file mode 100644
index 00000000000..45ef0b58a98
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp
@@ -0,0 +1,170 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellLiquidRateConstraint.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLLIQUIDRATECONSTRAINT_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLLIQUIDRATECONSTRAINT_HPP
+
+#include "common/format/EnumStrings.hpp"
+
+#include "functions/TableFunction.hpp"
+#include "WellConstraintsBase.hpp"
+
+namespace geos
+{
+
+
+/**
+ * @class LiquidRateConstraint
+ * @brief This class describes a Liquid rate constraint used to control of type WellConstraintType
+ */
+
+
+class LiquidRateConstraint : public WellConstraintBase
+{
+public:
+
+
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit LiquidRateConstraint( string const & name, dataRepository::Group * const parent );
+
+
+ /**
+ * @brief Default destructor.
+ */
+ ~LiquidRateConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ LiquidRateConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ LiquidRateConstraint( LiquidRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ LiquidRateConstraint( LiquidRateConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ LiquidRateConstraint & operator=( LiquidRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ LiquidRateConstraint & operator=( LiquidRateConstraint && ) = delete;
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "LiquidRateConstraint";
+ }
+ ///@}
+
+ /**
+ * @name Getters / Setters
+ */
+ ///@{
+ /**
+ * @brief Get the target phase name
+ * @return the target phase name
+ */
+ const string_array & getPhaseNames() const { return m_phaseNames; }
+
+ /**
+ * @brief Set phases associated with liquid constraint
+ * @param array of phase names
+ */
+ void setPhaseNames( const string_array & phaseNames ) { m_phaseNames=phaseNames; }
+
+ /**
+ * @brief Get the phase indices
+ * @return array of phase indices
+ */
+ const array1d< integer > & getPhaseIndices() const { return m_phaseIndices; }
+
+ ///@}
+ /**
+ * @brief Struct to serve as a container for variable strings and keys.
+ * @struct viewKeyStruct
+ */
+ struct viewKeyStruct
+ {
+ /// String key for the liquid rate
+ static constexpr char const * liquidRateString() { return "liquidRate"; }
+ /// String key for the phases names
+ static constexpr char const * phaseNamesString() { return "phaseNames"; }
+ };
+
+ // Temp interface - tjb
+ virtual ConstraintTypeId getControl() const override { return ConstraintTypeId::LIQUIDRATE; };
+
+ virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const override;
+
+protected:
+
+ virtual void postInputInitialization() override;
+
+ template< typename T >
+ void validateLiquidType( T const & fluidModel )
+ {
+ m_phaseIndices.resize( m_phaseNames.size());
+ for( size_t ip =0; ip m_phaseIndices;
+
+};
+
+
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLLiquidRateConstraint_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellMassRateConstraint.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellMassRateConstraint.cpp
new file mode 100644
index 00000000000..6851a033f8b
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellMassRateConstraint.cpp
@@ -0,0 +1,81 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellMassRateConstraints.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellMassRateConstraint.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+MassRateConstraint::MassRateConstraint( string const & name, Group * const parent )
+ : WellConstraintBase( name, parent )
+{
+ this->setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
+
+ this->registerWrapper( viewKeyStruct::massRateString(), &this->m_constraintValue ).
+ setDefaultValue( 0.0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::WRITE_AND_READ ).
+ setDescription( "Maximum mass rate (kg/s)" );
+}
+
+MassRateConstraint::~MassRateConstraint()
+{}
+
+
+void MassRateConstraint::postInputInitialization()
+{
+ // Validate table options
+ WellConstraintBase::postInputInitialization();
+
+ // check constraint value
+ GEOS_THROW_IF( m_constraintValue < 0,
+ getWrapperDataContext( viewKeyStruct::massRateString() ) << ": Target value is negative",
+ InputError );
+
+ GEOS_THROW_IF ((m_constraintValue <= 0.0 && m_constraintScheduleTableName.empty()),
+ getName() << " " << getDataContext() << ": You need to specify a mass rate constraint. \n" <<
+ "The rate constraint can be specified using " <<
+ "either " << viewKeyStruct::massRateString() <<
+ " or " << WellConstraintBase::viewKeyStruct::constraintScheduleTableNameString(),
+ InputError );
+}
+
+
+bool MassRateConstraint::checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime )const
+{
+ // isViolated is defined as a static method on the specific WellConstraintType (Injection/Production)
+ // Evaluate violation according to the sign set for injectors/producers
+ real64 const currentValue = currentConstraint.massRate();
+ real64 const constraintValue = this->getConstraintValue( currentTime );
+ if( this->m_rateSign < 0.0 )
+ {
+ return currentValue < constraintValue;
+ }
+ else
+ {
+ return currentValue > constraintValue;
+ }
+}
+} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp
new file mode 100644
index 00000000000..6cd6703ba36
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp
@@ -0,0 +1,120 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellMassRateConstraint.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLMASSRATECONSTRAINT_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLMASSRATECONSTRAINT_HPP
+
+#include "common/format/EnumStrings.hpp"
+#include "dataRepository/Group.hpp"
+#include "functions/TableFunction.hpp"
+#include "WellConstraintsBase.hpp"
+namespace geos
+{
+
+/**
+ * @class MassRateConstraint
+ * @brief This class describes a mass rate constraint used to control a well.
+ */
+
+class MassRateConstraint : public WellConstraintBase
+{
+public:
+
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit MassRateConstraint( string const & name, dataRepository::Group * const parent );
+
+
+ /**
+ * @brief Default destructor.
+ */
+ ~MassRateConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ MassRateConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ MassRateConstraint( MassRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ MassRateConstraint( MassRateConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ MassRateConstraint & operator=( MassRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ MassRateConstraint & operator=( MassRateConstraint && ) = delete;
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "MassRateConstraint";
+ }
+ ///@}
+
+ struct viewKeyStruct
+ {
+ /// String key for the well target rate
+ static constexpr char const * massRateString() { return "massRate"; }
+ };
+
+ /**
+ * @name Getters / Setters
+ */
+
+ // Temp interface - tjb
+ virtual ConstraintTypeId getControl() const override { return ConstraintTypeId::MASSRATE; };
+ ///@}
+
+ virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const override;
+
+protected:
+
+ virtual void postInputInitialization() override;
+
+};
+
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLMASSRATECONSTRAINT_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.cpp
new file mode 100644
index 00000000000..533848b97a3
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.cpp
@@ -0,0 +1,88 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellPhaseVolumeRateConstraint.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellPhaseVolumeRateConstraint.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+
+PhaseVolumeRateConstraint::PhaseVolumeRateConstraint( string const & name, Group * const parent )
+ : WellConstraintBase( name, parent )
+{
+ this->setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
+
+ this->registerWrapper( viewKeyStruct::phaseRateString(), &this->m_constraintValue ).
+ setDefaultValue( 0.0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::WRITE_AND_READ ).
+ setDescription( "Phase rate, (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s]) " );
+
+ this->registerWrapper( viewKeyStruct::phaseNameString(), &this->m_phaseName ).
+ setRTTypeName( rtTypes::CustomTypes::groupNameRef ).
+ setDefaultValue( "" ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::WRITE_AND_READ ).
+ setDescription( "Name of the target phase" );
+}
+
+PhaseVolumeRateConstraint::~PhaseVolumeRateConstraint()
+{}
+
+void PhaseVolumeRateConstraint::postInputInitialization()
+{
+ // Validate table options
+ WellConstraintBase::postInputInitialization();
+
+ // check constraint value
+ GEOS_THROW_IF( m_constraintValue < 0,
+ getWrapperDataContext( viewKeyStruct::phaseRateString() ) << ": Target value is negative",
+ InputError );
+
+
+ GEOS_THROW_IF ((m_constraintValue <= 0.0 && m_constraintScheduleTableName.empty()),
+ getName() << " " << getDataContext() << ": You need to specify a phase rate constraint. \n" <<
+ "The rate constraint can be specified using " <<
+ "either " << viewKeyStruct::phaseRateString() <<
+ " or " << WellConstraintBase::viewKeyStruct::constraintScheduleTableNameString(),
+ InputError );
+}
+
+bool PhaseVolumeRateConstraint::checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const
+{
+ real64 const currentValue = currentConstraint.phaseVolumeRates()[m_phaseIndex];
+ real64 const constraintValue = getConstraintValue( currentTime );
+ if( m_rateSign < 0.0 )
+ {
+ return currentValue < constraintValue;
+ }
+ else
+ {
+ return currentValue > constraintValue;
+ }
+}
+
+} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp
new file mode 100644
index 00000000000..bb7880cfc0c
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp
@@ -0,0 +1,179 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellPhaseVolumeRateConstraint.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLPHASEVOLUMERATECONSTRAINT_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLPHASEVOLUMERATECONSTRAINT_HPP
+
+#include "common/format/EnumStrings.hpp"
+#include "dataRepository/Group.hpp"
+#include "functions/TableFunction.hpp"
+#include "WellConstraintsBase.hpp"
+#include "WellConstants.hpp"
+
+namespace geos
+{
+
+
+template< typename T >
+localIndex getPhaseIndexFromFluidModel( T const & fluidModel, std::string const & inputPhase )
+{
+ localIndex phaseIndex=-1;
+ // Find target phase index for phase rate constraint
+ for( integer ip = 0; ip < fluidModel.numFluidPhases(); ++ip )
+ {
+ if( fluidModel.phaseNames()[ip] == inputPhase )
+ {
+ phaseIndex = ip;
+ }
+ }
+ return phaseIndex;
+}
+
+/**
+ * @class PhaseVolumeRateConstraint
+ * @brief This class describes a phase rate constraint used to control a well of WellConstraintType type (Injection or Production).
+ */
+
+class PhaseVolumeRateConstraint : public WellConstraintBase
+{
+public:
+
+
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit PhaseVolumeRateConstraint( string const & name, dataRepository::Group * const parent );
+
+ /**
+ * @brief Default destructor.
+ */
+ ~PhaseVolumeRateConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ PhaseVolumeRateConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ PhaseVolumeRateConstraint( PhaseVolumeRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ PhaseVolumeRateConstraint( PhaseVolumeRateConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ PhaseVolumeRateConstraint & operator=( PhaseVolumeRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ PhaseVolumeRateConstraint & operator=( PhaseVolumeRateConstraint && ) = delete;
+
+ ///@}
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "PhaseVolumeRateConstraint";
+ }
+
+ /**
+ * @name Getters / Setters
+ */
+ ///@{
+
+ // Temp interface - tjb
+ virtual ConstraintTypeId getControl() const override { return ConstraintTypeId::PHASEVOLRATE; };
+
+ /**
+ * @brief Get the target phase name
+ * @return the target phase name
+ */
+ const string & getPhaseName() const { return m_phaseName; }
+
+ /**
+ * @brief Get the target phase index
+ * @return the target phase index
+ */
+ const localIndex & getPhaseIndex() const { return m_phaseIndex; }
+
+ ///@}
+
+ struct viewKeyStruct
+ {
+ /// String key for the well target phase rate
+ static constexpr char const * phaseRateString() { return "phaseRate"; }
+ /// String key for the well target phase name
+ static constexpr char const * phaseNameString() { return "phaseName"; }
+ };
+
+ /**
+ * @brief Validate phase type is consistent with fluidmodel
+ */
+ template< typename T > void validatePhaseType( T const & fluidModel );
+ ///@}
+
+ virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const override;
+protected:
+
+ virtual void postInputInitialization() override;
+
+private:
+
+ /// Name of the targeted phase
+ string m_phaseName;
+
+ /// Index of the target phase, used to impose the phase rate constraint
+ localIndex m_phaseIndex;
+
+};
+
+template< typename T >
+void PhaseVolumeRateConstraint::validatePhaseType( T const & fluidModel )
+{
+ // Find target phase index for phase rate constraint
+ m_phaseIndex = getPhaseIndexFromFluidModel( fluidModel, this->template getReference< string >( viewKeyStruct::phaseNameString()));
+
+ GEOS_THROW_IF( m_phaseIndex == -1,
+ "PhaseVolumeRateConstraint " << this->template getReference< string >( viewKeyStruct::phaseNameString()) <<
+ ": Invalid phase type for simulation fluid model",
+ InputError );
+}
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLPHASEVOLUMERATECONSTRAINT_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellProductionConstraint.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellProductionConstraint.cpp
new file mode 100644
index 00000000000..4ec3ec3299d
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellProductionConstraint.cpp
@@ -0,0 +1,70 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellProductionConstraint.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellProductionConstraint.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+#include "WellLiquidRateConstraint.hpp"
+#include "WellMassRateConstraint.hpp"
+#include "WellPhaseVolumeRateConstraint.hpp"
+#include "WellVolumeRateConstraint.hpp"
+
+namespace geos
+{
+
+template< typename ConstraintRateType >
+ProductionConstraint< ConstraintRateType >::ProductionConstraint( string const & name, Group * const parent )
+ : ConstraintRateType( name, parent )
+{
+ // set rate sign for producers (base class member)
+ this->m_rateSign = -1.0;
+}
+template< typename ConstraintRateType >
+ProductionConstraint< ConstraintRateType >::~ProductionConstraint()
+{}
+
+template< typename ConstraintRateType >
+void ProductionConstraint< ConstraintRateType >::postInputInitialization()
+{
+ // Validate value and table options
+ ConstraintRateType::postInputInitialization();
+
+}
+// Register concrete wrapper constraint types and instantiate templates.
+
+template class ProductionConstraint< LiquidRateConstraint >;
+using ProductionLiquidRateConstraint = ProductionConstraint< LiquidRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, ProductionLiquidRateConstraint, string const &, Group * const )
+
+template class ProductionConstraint< MassRateConstraint >;
+using ProductionMassRateConstraint = ProductionConstraint< MassRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, ProductionMassRateConstraint, string const &, Group * const )
+
+template class ProductionConstraint< PhaseVolumeRateConstraint >;
+using ProductionPhaseVolumeRateConstraint = ProductionConstraint< PhaseVolumeRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, ProductionPhaseVolumeRateConstraint, string const &, Group * const )
+
+template class ProductionConstraint< VolumeRateConstraint >;
+using ProductionVolumeRateConstraint = ProductionConstraint< VolumeRateConstraint >;
+REGISTER_CATALOG_ENTRY( WellConstraintBase, ProductionVolumeRateConstraint, string const &, Group * const )
+
+} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellProductionConstraint.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellProductionConstraint.hpp
new file mode 100644
index 00000000000..ce1ca16de14
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellProductionConstraint.hpp
@@ -0,0 +1,106 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellProductionConstraints.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLPRODUCTIONCONSTRAINT_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLPRODUCTIONCONSTRAINT_HPP
+
+#include "common/format/EnumStrings.hpp"
+#include "dataRepository/Group.hpp"
+#include "functions/TableFunction.hpp"
+
+namespace geos
+{
+using namespace dataRepository;
+/**
+ * @class ProductionConstraint
+ * @brief This class describes constraint used to control a production well.
+ */
+
+template< typename ConstraintType >
+class ProductionConstraint : public ConstraintType
+{
+public:
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit ProductionConstraint( string const & name, dataRepository::Group * const parent );
+
+ /**
+ * @brief Default destructor.
+ */
+ ~ProductionConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ ProductionConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ ProductionConstraint( ProductionConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ ProductionConstraint( ProductionConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ ProductionConstraint & operator=( ProductionConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ ProductionConstraint & operator=( ProductionConstraint && ) = delete;
+
+ ///@}
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "Production"+ConstraintType::catalogName();
+ }
+ virtual string getCatalogName() const override { return catalogName(); }
+protected:
+
+ virtual void postInputInitialization() override;
+
+ static bool isViolated( const real64 & currentValue, const real64 & constraintValue )
+ { return currentValue < constraintValue; }
+};
+
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLPRODUCTIONCONSTRAINT_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp
index daeeffef3c1..79470d0865a 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp
@@ -43,7 +43,9 @@ WellSolverBase::WellSolverBase( string const & name,
m_numDofPerResElement( 0 ),
m_isThermal( 0 ),
m_ratesOutputDir( joinPath( OutputBase::getOutputDirectory(), name + "_rates" ) ),
- m_keepVariablesConstantDuringInitStep( false )
+ m_keepVariablesConstantDuringInitStep( false ),
+
+ m_useNewCode( true )
{
registerWrapper( viewKeyStruct::isThermalString(), &m_isThermal ).
setApplyDefaultValue( 0 ).
@@ -63,6 +65,12 @@ WellSolverBase::WellSolverBase( string const & name,
setInputFlag( dataRepository::InputFlags::OPTIONAL ).
setDescription( "Choose time step to honor rates/bhp tables time intervals" );
+ this->registerWrapper( viewKeyStruct::useNewCodeString(), &m_useNewCode ).
+ setApplyDefaultValue( 1 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setDescription( "Use new code" );
+
+
addLogLevel< logInfo::WellControl >();
}
@@ -294,8 +302,73 @@ void WellSolverBase::implicitStepSetup( real64 const & time_n,
setPerforationStatus( time_n, domain );
// Initialize the primary and secondary variables for the first time step
+ if( !m_useNewCode )
+ {
+ initializeWells( domain, time_n );
+ }
+
+}
+
+void WellSolverBase::selectWellConstraint( real64 const & time_n,
+ real64 const & dt,
+ const integer coupledIterationNumber,
+ DomainPartition & domain )
+{
+ GEOS_MARK_FUNCTION;
+ GEOS_UNUSED_VAR( dt );
+ GEOS_UNUSED_VAR( coupledIterationNumber );
+
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const & meshBodyName,
+ MeshLevel & meshLevel,
+ string_array const & regionNames )
+ {
+ GEOS_UNUSED_VAR( meshBodyName );
+ ElementRegionManager & elementRegionManager = meshLevel.getElemManager();
+ elementRegionManager.forElementRegions< WellElementRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementRegion & region )
+ {
+ WellElementSubRegion & subRegion = region.getGroup( ElementRegionBase::viewKeyStruct::elementSubRegions() )
+ .getGroup< WellElementSubRegion >( region.getSubRegionName() );
+ WellControls & wellControls = getWellControls( subRegion );
+ if( wellControls.isWellOpen() )
+ {
+ if( !wellControls.getWellState() )
+ {
+ wellControls.setWellState( 1 );
+
+ initializeWell( domain, meshLevel, subRegion, time_n );
+ }
+ }
+ else
+ {
+ wellControls.setWellState( 0 );
+ }
+
+
+ if( wellControls.getWellState())
+ {
+ wellControls.setConstraintSwitch( false );
+
+ evaluateConstraints( time_n,
+ subRegion );
+
+ // If a well is opened and then timestep is cut resulting in the well being shut, if the well is opened
+ // the well initialization code requires control type to by synced
+ integer owner = -1;
+ // Only subregion owner evaluates well control and control changes need to be broadcast to all ranks
+ if( subRegion.isLocallyOwned() )
+ {
+ owner = MpiWrapper::commRank( MPI_COMM_GEOS );
+ }
+ owner = MpiWrapper::max( owner );
+ WellControls::Control wellControl = wellControls.getControl();
+ MpiWrapper::broadcast( wellControl, owner );
+ wellControls.setControl( wellControl );
+ }
+ } );
+ } );
- initializeWells( domain, time_n );
}
void WellSolverBase::updateState( DomainPartition & domain )
@@ -319,13 +392,43 @@ void WellSolverBase::assembleSystem( real64 const time,
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- string const wellDofKey = dofManager.getKey( wellElementDofName());
+
+ if( m_useNewCode )
+ {
+ // selects constraints one of 2 ways
+ // wellEstimator flag set to 0 => orginal logic rates are computed during update state and constraints are selected every newton
+ // iteration
+ // wellEstimator flag > 0 => well esitmator solved for each constraint and then selects the constraint
+ // => estimator solve only performed first "wellEstimator" iterations
+ NonlinearSolverParameters const & nonlinearParams = getNonlinearSolverParameters();
+ selectWellConstraint( time, dt, nonlinearParams.m_numNewtonIterations, domain );
+ }
+
// assemble the accumulation term in the mass balance equations
assembleAccumulationTerms( time, dt, domain, dofManager, localMatrix, localRhs );
// then assemble the pressure relations between well elements
assemblePressureRelations( time, dt, domain, dofManager, localMatrix, localRhs );
+ //if( false && m_useNewCode )
+ {
+ forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
+ MeshLevel & mesh,
+ string_array const & regionNames )
+ {
+ ElementRegionManager & elementRegionManager = mesh.getElemManager();
+ elementRegionManager.forElementRegions< WellElementRegion >( regionNames,
+ [&]( localIndex const,
+ WellElementRegion & region )
+ {
+ WellElementSubRegion & subRegion = region.getGroup( ElementRegionBase::viewKeyStruct::elementSubRegions() )
+ .getGroup< WellElementSubRegion >( region.getSubRegionName() );
+ WellControls & wellControls = getWellControls( subRegion );
+ if( !wellControls.getConstraintSwitch() )
+ assembleWellConstraintTerms( time, dt, subRegion, dofManager, localMatrix.toViewConstSizes(), localRhs );
+ } );
+ } );
+ }
// then compute the perforation rates (later assembled by the coupled solver)
computePerforationRates( time, dt, domain );
@@ -387,8 +490,15 @@ void WellSolverBase::precomputeData( DomainPartition & domain )
wellElemGravCoef[iwelem] = LvArray::tensorOps::AiBi< 3 >( wellElemLocation[iwelem], gravVector );
} );
+ wellControls.forSubGroups< BHPConstraint >( [&]( auto & constraint )
+ {
+ // set the reference well element where the BHP control is applied
+ real64 const refElev1 = constraint.getReferenceElevation();
+ constraint.setReferenceGravityCoef( refElev1 * gravVector[2] );
+ } );
+
// set the reference well element where the BHP control is applied
- wellControls.setReferenceGravityCoef( refElev * gravVector[2] );
+ wellControls.setReferenceGravityCoef( refElev * gravVector[2] ); // tjb remove
} );
} );
}
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp
index a8159378b50..ae1ff3194db 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp
@@ -159,6 +159,12 @@ class WellSolverBase : public PhysicsSolverBase
virtual void registerDataOnMesh( Group & meshBodies ) override;
+ void selectWellConstraint( real64 const & time_n,
+ real64 const & dt,
+ integer const coupledIterationNumber,
+ DomainPartition & domain );
+
+
virtual void setupDofs( DomainPartition const & domain,
DofManager & dofManager ) const override;
@@ -180,15 +186,6 @@ class WellSolverBase : public PhysicsSolverBase
/**@}*/
- /**
- * @brief function to assemble the linear system matrix and rhs
- * @param time the time at the beginning of the step
- * @param dt the desired timestep
- * @param domain the domain partition
- * @param dofManager degree-of-freedom manager associated with the linear system
- * @param matrix the system matrix
- * @param rhs the system right-hand side vector
- */
virtual void assembleSystem( real64 const time,
real64 const dt,
DomainPartition & domain,
@@ -196,6 +193,14 @@ class WellSolverBase : public PhysicsSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) override;
+ virtual void assembleWellFluxTerms( real64 const & GEOS_UNUSED_PARAM( time ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & GEOS_UNUSED_PARAM( subRegion ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
+ arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) = 0;
+
+
/**
* @brief assembles the flux terms for all connections between well elements
* @param time_n previous time value
@@ -212,6 +217,16 @@ class WellSolverBase : public PhysicsSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) = 0;
+
+
+ virtual void assembleWellAccumulationTerms( real64 const & time,
+ real64 const & dt,
+ WellElementSubRegion & subRegion,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs ) = 0;
+
+
/**
* @brief assembles the accumulation term for all the well elements
* @param domain the physical domain object
@@ -226,8 +241,22 @@ class WellSolverBase : public PhysicsSolverBase
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs ) = 0;
+ virtual void assembleWellConstraintTerms( real64 const & GEOS_UNUSED_PARAM( time ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & GEOS_UNUSED_PARAM( subRegion ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
+ arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) = 0;
+
+ virtual void assembleWellPressureRelations ( real64 const & GEOS_UNUSED_PARAM( time ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & GEOS_UNUSED_PARAM( subRegion ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ CRSMatrixView< real64, globalIndex const > const & GEOS_UNUSED_PARAM( localMatrix ),
+ arrayView1d< real64 > const & GEOS_UNUSED_PARAM( localRhs ) ) = 0;
/**
- * @brief assembles the pressure relations at all connections between well elements except at the well head
+ * @brief assembles the pressure relations at all connections between well elements except at
+ * the well head
* @param time_n time at the beginning of the time step
* @param dt the time step size
* @param domain the physical domain object
@@ -243,17 +272,34 @@ class WellSolverBase : public PhysicsSolverBase
arrayView1d< real64 > const & localRhs ) = 0;
/**
- * @brief Recompute all dependent quantities from primary variables (including constitutive models)
+ * @brief Recompute all dependent quantities from primary variables (including constitutive
+ * models)
* @param domain the domain containing the mesh and fields
*/
+ virtual real64 updateWellState( WellElementSubRegion & subRegion ) = 0;
virtual void updateState( DomainPartition & domain ) override;
/**
- * @brief Recompute all dependent quantities from primary variables (including constitutive models)
- * @param subRegion the well subRegion containing the well elements and their associated fields
+ * @brief Initialize all the primary and secondary variables in all the wells
+ * @param domain the domain containing the well manager to access individual wells
+ */
+ virtual void initializeWells( DomainPartition & domain, real64 const & time_n ) = 0;
+ virtual void initializeWell( DomainPartition & domain, MeshLevel & mesh, WellElementSubRegion & subRegion, real64 const & time_n ) = 0;
+
+ /**
+ * @brief Recompute all dependent quantities from primary variables (including constitutive
+ * models)
+ * @param subRegion the well subRegion containing the well elements and their associated
+ * fields
*/
virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) = 0;
+
+ virtual void computeWellPerforationRates( real64 const & GEOS_UNUSED_PARAM( time_n ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ ElementRegionManager const & GEOS_UNUSED_PARAM( elemManager ),
+ WellElementSubRegion & GEOS_UNUSED_PARAM( subRegion ) ){}
+
/**
* @brief Recompute the perforation rates for all the wells
* @param domain the domain containing the mesh and fields
@@ -262,6 +308,67 @@ class WellSolverBase : public PhysicsSolverBase
real64 const & dt,
DomainPartition & domain ) = 0;
+ virtual real64
+ calculateWellResidualNorm( real64 const & GEOS_UNUSED_PARAM( time_n ),
+ real64 const & GEOS_UNUSED_PARAM( dt ),
+ WellElementSubRegion const & GEOS_UNUSED_PARAM( subRegion ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localRhs ) ) = 0;
+
+ virtual real64
+ scalingForWellSystemSolution( ElementSubRegionBase & GEOS_UNUSED_PARAM( subRegion ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ) ) = 0;
+
+ virtual bool
+ checkWellSystemSolution( ElementSubRegionBase & GEOS_UNUSED_PARAM( subRegion ),
+ DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ),
+ real64 const GEOS_UNUSED_PARAM( scalingFactor ) ) = 0;
+ virtual void
+ applyWellSystemSolution( DofManager const & GEOS_UNUSED_PARAM( dofManager ),
+ arrayView1d< real64 const > const & GEOS_UNUSED_PARAM( localSolution ),
+ real64 const GEOS_UNUSED_PARAM( scalingFactor ),
+ real64 const GEOS_UNUSED_PARAM( dt ),
+ DomainPartition & GEOS_UNUSED_PARAM( domain ),
+ MeshLevel & GEOS_UNUSED_PARAM( mesh ),
+ WellElementSubRegion & GEOS_UNUSED_PARAM( subRegion ) ) = 0;
+
+ /**
+ * @brief Function to perform line search
+ * @param time_n time at the beginning of the step
+ * @param dt the perscribed timestep
+ * @param cycleNumber the current cycle number
+ * @param domain the domain object
+ * @param dofManager degree-of-freedom manager associated with the linear system
+ * @param localMatrix the system matrix
+ * @param rhs the system right-hand side vector
+ * @param solution the solution vector
+ * @param scaleFactor the scaling factor to apply to the solution
+ * @param lastResidual (in) target value below which to reduce residual norm, (out) achieved
+ * residual norm
+ * @return return true if line search succeeded, false otherwise
+ *
+ * This function implements a nonlinear newton method for implicit problems. It requires that
+ * the
+ * other functions in the solver interface are implemented in the derived physics solver. The
+ * nonlinear loop includes a simple line search algorithm, and will cut the timestep if
+ * convergence is not achieved according to the parameters in linearSolverParameters member.
+ */
+ bool
+ lineSearch1( real64 const & time_n,
+ real64 const & dt,
+ integer const cycleNumber,
+ DomainPartition & domain,
+ ElementRegionManager & elemManager,
+ WellElementSubRegion & subRegion,
+ MeshLevel & mesh,
+ DofManager const & dofManager,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ ParallelVector & rhs,
+ ParallelVector & solution,
+ real64 const scaleFactor,
+ real64 & lastResidual );
/**
* @brief function to set the next time step size
* @param[in] currentTime the current time
@@ -274,9 +381,12 @@ class WellSolverBase : public PhysicsSolverBase
DomainPartition & domain ) override;
/**
- * @brief Utility function to keep the well variables during a time step (used in poromechanics simulations)
- * @param[in] keepVariablesConstantDuringInitStep flag to tell the solver to freeze its primary variables during a time step
- * @detail This function is meant to be called by a specific task before/after the initialization step
+ * @brief Utility function to keep the well variables during a time step (used in
+ * poromechanics simulations)
+ * @param[in] keepVariablesConstantDuringInitStep flag to tell the solver to freeze its
+ * primary variables during a time step
+ * @detail This function is meant to be called by a specific task before/after the
+ * initialization step
*/
void setKeepVariablesConstantDuringInitStep( bool const keepVariablesConstantDuringInitStep )
{ m_keepVariablesConstantDuringInitStep = keepVariablesConstantDuringInitStep; }
@@ -286,6 +396,7 @@ class WellSolverBase : public PhysicsSolverBase
static constexpr char const * isThermalString() { return "isThermal"; }
static constexpr char const * writeCSVFlagString() { return "writeCSV"; }
static constexpr char const * timeStepFromTablesFlagString() { return "timeStepFromTables"; }
+ static constexpr char const * useNewCodeString() { return "useNewCode"; }
static constexpr char const * fluidNamesString() { return "fluidNames"; }
};
@@ -306,11 +417,6 @@ class WellSolverBase : public PhysicsSolverBase
virtual void initializePostSubGroups() override;
- /**
- * @brief Initialize all the primary and secondary variables in all the wells
- * @param domain the domain containing the well manager to access individual wells
- */
- virtual void initializeWells( DomainPartition & domain, real64 const & time_n ) = 0;
/**
* @brief Make sure that the well constraints are compatible
@@ -327,6 +433,10 @@ class WellSolverBase : public PhysicsSolverBase
real64 const & dt,
DomainPartition & domain ) = 0;
+ virtual bool evaluateConstraints( real64 const & time_n,
+ WellElementSubRegion & subRegion ) = 0;
+
+
/// name of the flow solver
string m_flowSolverName;
@@ -357,6 +467,13 @@ class WellSolverBase : public PhysicsSolverBase
/// name of the fluid constitutive model used as a reference for component/phase description
string m_referenceFluidModelName;
+
+ /// flag to use the estimator
+ integer m_estimateSolution;
+
+
+ integer m_useNewCode;
+
};
}
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.cpp
new file mode 100644
index 00000000000..db11dd85ef2
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.cpp
@@ -0,0 +1,80 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellVolumeRateConstraint.cpp
+ */
+
+#include "LogLevelsInfo.hpp"
+#include "WellVolumeRateConstraint.hpp"
+#include "WellConstants.hpp"
+#include "dataRepository/InputFlags.hpp"
+#include "functions/FunctionManager.hpp"
+
+namespace geos
+{
+
+using namespace dataRepository;
+
+VolumeRateConstraint::VolumeRateConstraint( string const & name, Group * const parent )
+ : WellConstraintBase( name, parent )
+{
+ this->setInputFlags( InputFlags::OPTIONAL_NONUNIQUE );
+
+ this->registerWrapper( viewKeyStruct::volumeRateString(), &this->m_constraintValue ).
+ setDefaultValue( 0.0 ).
+ setInputFlag( InputFlags::OPTIONAL ).
+ setRestartFlags( RestartFlags::WRITE_AND_READ ).
+ setDescription( "Volumetric rate (if useSurfaceConditions: [surface m^3/s]; else [reservoir m^3/s])" );
+
+}
+
+VolumeRateConstraint::~VolumeRateConstraint()
+{}
+
+
+void VolumeRateConstraint::postInputInitialization()
+{
+ // Validate table options
+ WellConstraintBase::postInputInitialization();
+
+ // check constraint value
+ GEOS_THROW_IF( m_constraintValue < 0,
+ getWrapperDataContext( viewKeyStruct::volumeRateString() ) << ": Target value is negative",
+ InputError );
+
+ GEOS_THROW_IF ((m_constraintValue <= 0.0 && m_constraintScheduleTableName.empty()),
+ getName() << " " << getDataContext() << ": You need to specify a volume rate constraint. \n" <<
+ "The rate constraint can be specified using " <<
+ "either " << viewKeyStruct::volumeRateString() <<
+ " or " << WellConstraintBase::viewKeyStruct::constraintScheduleTableNameString(),
+ InputError );
+}
+
+bool VolumeRateConstraint::checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const
+{
+ real64 const currentValue = currentConstraint.totalVolumeRate();
+ real64 const constraintValue = this->getConstraintValue( currentTime );
+ if( this->m_rateSign < 0.0 )
+ {
+ return currentValue < constraintValue;
+ }
+ else
+ {
+ return currentValue > constraintValue;
+ }
+}
+
+} //namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp
new file mode 100644
index 00000000000..1ed14597ca3
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp
@@ -0,0 +1,124 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 WellVolumeRateConstraints.hpp
+ */
+
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTOTALVOLRATECONSTRAINTS_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLTOTALVOLRATECONSTRAINTS_HPP
+
+#include "common/format/EnumStrings.hpp"
+#include "dataRepository/Group.hpp"
+#include "functions/TableFunction.hpp"
+#include "WellConstraintsBase.hpp"
+namespace geos
+{
+
+
+
+/**
+ * @class VolumeRateConstraint
+ * @brief This class describes a volume rate constraint used to control a well.
+ */
+
+class VolumeRateConstraint : public WellConstraintBase
+{
+public:
+
+ /**
+ * @name Constructor / Destructor
+ */
+ ///@{
+
+ /**
+ * @brief Constructor for WellControls Objects.
+ * @param[in] name the name of this instantiation of WellControls in the repository
+ * @param[in] parent the parent group of this instantiation of WellControls
+ */
+ explicit VolumeRateConstraint( string const & name, dataRepository::Group * const parent );
+
+
+ /**
+ * @brief Default destructor.
+ */
+ ~VolumeRateConstraint() override;
+
+ /**
+ * @brief Deleted default constructor.
+ */
+ VolumeRateConstraint() = delete;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ VolumeRateConstraint( VolumeRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ */
+ VolumeRateConstraint( VolumeRateConstraint && ) = delete;
+
+ /**
+ * @brief Deleted assignment operator.
+ * @return a reference to a constraint object
+ */
+ VolumeRateConstraint & operator=( VolumeRateConstraint const & ) = delete;
+
+ /**
+ * @brief Deleted move operator.
+ * @return a reference to a constraint object
+ */
+ VolumeRateConstraint & operator=( VolumeRateConstraint && ) = delete;
+
+ /**
+ * @brief name of the node manager in the object catalog
+ * @return string that contains the catalog name to generate a new Constraint object through the object catalog.
+ */
+ static string catalogName()
+ {
+ return "VolumeRateConstraint";
+ }
+ ///@}
+ /**
+ * @brief Struct to serve as a container for variable strings and keys.
+ * @struct viewKeyStruct
+ */
+ struct viewKeyStruct
+ {
+ /// String key for the volume rate
+ static constexpr char const * volumeRateString() { return "volumeRate"; }
+ };
+ /**
+ * @name Getters / Setters
+ */
+ ///@{
+
+ // Temp interface - tjb
+ virtual ConstraintTypeId getControl() const override { return ConstraintTypeId::TOTALVOLRATE; };
+ ///@}
+
+ virtual bool checkViolation( WellConstraintBase const & currentConstraint, real64 const & currentTime ) const override;
+protected:
+
+ virtual void postInputInitialization() override;
+
+};
+
+
+} //namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINT_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellConstraintKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellConstraintKernels.hpp
new file mode 100644
index 00000000000..485545cd2d9
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellConstraintKernels.hpp
@@ -0,0 +1,555 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 CompositionalMultiphaseWellConstraintKernels.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINTKERNELS_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINTKERNELS_HPP
+
+#include "codingUtilities/Utilities.hpp"
+#include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
+#include "constitutive/fluid/multifluid/MultiFluidFields.hpp"
+
+
+#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp"
+namespace geos
+{
+
+namespace wellConstraintKernels
+{
+
+/******************************** ControlEquationHelper ********************************/
+//template< integer NC, integer IS_THERMAL, typname S, typename T >
+//struct ConstraintHelper< NC, IS_THERMAL > {};
+
+template< integer NC, integer IS_THERMAL, typename CONSTRAINT = BHPConstraint >
+struct ConstraintHelper
+{
+ static void assembleConstraintEquation( real64 const & time_n,
+ WellControls & wellControls,
+ BHPConstraint & constraint,
+ WellElementSubRegion const & subRegion,
+ string const & wellDofKey,
+ localIndex const & rankOffset,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // subRegion data
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >();
+ arrayView1d< real64 const > const & totalMassDens = subRegion.getField< fields::well::totalMassDensity >();
+ arrayView2d< real64 const > const & dTotalMassDens = subRegion.getField< fields::well::dTotalMassDensity >();
+ arrayView1d< real64 const > const wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >();
+
+ // setup row/column indices for constraint equation
+ using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
+ using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >;
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ localIndex const eqnRowIndex = wellElemDofNumber[iwelemRef] + WJ_ROFFSET::CONTROL - rankOffset;
+ globalIndex dofColIndices[COFFSET_WJ::nDer]{};
+ for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic )
+ {
+ dofColIndices[ ic ] = wellElemDofNumber[iwelemRef] + ic;
+ }
+
+ // constraint data
+ real64 const & targetBHP = constraint.getConstraintValue( time_n );
+ real64 const & refGravCoef = constraint.getReferenceGravityCoef();
+
+ // current constraint value
+ real64 const & currentBHP =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
+
+ // residual
+ real64 controlEqn = currentBHP - targetBHP;
+
+ // setup Jacobian terms
+ real64 dControlEqn[NC+2+IS_THERMAL]{};
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [pres,
+ totalMassDens,
+ dTotalMassDens,
+ wellElemGravCoef,
+ &dControlEqn,
+ &iwelemRef,
+ &refGravCoef] ( localIndex const )
+ {
+ real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef];
+ dControlEqn[COFFSET_WJ::dP] = 1 + dTotalMassDens[iwelemRef][Deriv::dP] * diffGravCoef;
+ for( integer ic = 0; ic < NC; ++ic )
+ {
+ dControlEqn[COFFSET_WJ::dC+ic] = dTotalMassDens[iwelemRef][Deriv::dC+ic] * diffGravCoef;
+ }
+ if constexpr ( IS_THERMAL )
+ {
+ dControlEqn[COFFSET_WJ::dT] = dTotalMassDens[iwelemRef][Deriv::dT] * diffGravCoef;
+ }
+ } );
+
+ // add solver matrices
+ localRhs[eqnRowIndex] += controlEqn;
+ localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
+ dofColIndices,
+ dControlEqn,
+ COFFSET_WJ::nDer );
+ }
+
+
+ template< template< typename U > class T, typename U=PhaseVolumeRateConstraint >
+ static void assembleConstraintEquation( real64 const & time_n,
+ WellControls & wellControls,
+ T< PhaseVolumeRateConstraint > & constraint,
+ WellElementSubRegion const & subRegion,
+ string const & wellDofKey,
+ localIndex const & rankOffset,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // subRegion data
+
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >();
+ arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >();
+ arrayView3d< real64 const, compflow::USD_COMP_DC > const & dCompFrac_dCompDens = subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >();
+
+ // setup row/column indices for constraint equation
+ using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
+ using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >;
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ localIndex const eqnRowIndex = wellElemDofNumber[iwelemRef] + WJ_ROFFSET::CONTROL - rankOffset;
+ globalIndex dofColIndices[COFFSET_WJ::nDer]{};
+ for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic )
+ {
+ dofColIndices[ ic ] = wellElemDofNumber[iwelemRef] + ic;
+ }
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
+
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseFrac = fluidSeparator.phaseFraction();
+ arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const & dPhaseFrac = fluidSeparator.dPhaseFraction();
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDens = fluidSeparator.phaseDensity();
+ arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const & dPhaseDens = fluidSeparator.dPhaseDensity();
+
+ // constraint data
+ integer ip = getPhaseIndexFromFluidModel( fluidSeparator, constraint.getPhaseName());
+ real64 const & targetPhaseRate = constraint.getConstraintValue( time_n );
+
+ // current constraint value
+ arrayView1d< real64 > const & currentPhaseVolRate =
+ wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+
+ // residual
+ real64 controlEqn = currentPhaseVolRate[ip] - targetPhaseRate;
+
+ // setup Jacobian terms
+ real64 dControlEqn[NC+2+IS_THERMAL]{};
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [&ip,
+ connRate,
+ phaseDens,
+ dPhaseDens,
+ phaseFrac,
+ dPhaseFrac,
+ compFrac,
+ dCompFrac_dCompDens,
+ &dControlEqn,
+ &useSurfaceConditions,
+ &iwelemRef] ( localIndex const )
+ {
+ // skip the rest of this function if phase ip is absent
+ bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0);
+ if( phaseExists )
+ {
+ stackArray1d< real64, NC > work( NC );
+ real64 const currentTotalRate = connRate[iwelemRef];
+
+ real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip];
+ real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv;
+ real64 const dPhaseFracTimesPhaseDensInv_dPres = dPhaseFrac[iwelemRef][0][ip][Deriv::dP] * phaseDensInv
+ - dPhaseDens[iwelemRef][0][ip][Deriv::dP] * phaseFracTimesPhaseDensInv * phaseDensInv;
+
+ // divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate
+ dControlEqn[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres;
+ dControlEqn[COFFSET_WJ::dQ] = phaseFracTimesPhaseDensInv;
+ if constexpr (IS_THERMAL )
+ {
+ real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv
+ - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv;
+ dControlEqn[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp;
+ }
+
+ for( integer ic = 0; ic < NC; ++ic )
+ {
+ dControlEqn[COFFSET_WJ::dC+ic] = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv;
+ dControlEqn[COFFSET_WJ::dC+ic] += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv;
+ dControlEqn[COFFSET_WJ::dC+ic] *= currentTotalRate;
+ }
+ applyChainRuleInPlace( NC, dCompFrac_dCompDens[iwelemRef], &dControlEqn[COFFSET_WJ::dC], work.data() );
+
+ }
+ } );
+
+ // add solver matrices
+ localRhs[eqnRowIndex] += controlEqn;
+ localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
+ dofColIndices,
+ dControlEqn,
+ COFFSET_WJ::nDer );
+ }
+
+ template< template< typename U > class T, typename U=LiquidRateConstraint >
+ static void assembleConstraintEquation( real64 const & time_n,
+ WellControls & wellControls,
+ T< LiquidRateConstraint > & constraint,
+ WellElementSubRegion const & subRegion,
+ string const & wellDofKey,
+ localIndex const & rankOffset,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // subRegion data
+
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >();
+ arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >();
+ arrayView3d< real64 const, compflow::USD_COMP_DC > const & dCompFrac_dCompDens = subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >();
+
+ // setup row/column indices for constraint equation
+ using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
+ using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >;
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ localIndex const eqnRowIndex = wellElemDofNumber[iwelemRef] + WJ_ROFFSET::CONTROL - rankOffset;
+ globalIndex dofColIndices[COFFSET_WJ::nDer]{};
+ for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic )
+ {
+ dofColIndices[ ic ] = wellElemDofNumber[iwelemRef] + ic;
+ }
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
+
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseFrac = fluidSeparator.phaseFraction();
+ arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const & dPhaseFrac = fluidSeparator.dPhaseFraction();
+ arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDens = fluidSeparator.phaseDensity();
+ arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_DC > const & dPhaseDens = fluidSeparator.dPhaseDensity();
+
+ // constraint data
+ real64 const & targetPhaseRate = constraint.getConstraintValue( time_n );
+ const array1d< int > & phaseIndices = constraint.getPhaseIndices();
+
+
+ // current constraint value
+ arrayView1d< real64 > const & currentPhaseVolRate =
+ wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+
+ // residual
+ real64 controlEqn = -targetPhaseRate;
+ for( integer ip= 0; ip < phaseIndices.size(); ++ip )
+ {
+ controlEqn += currentPhaseVolRate[phaseIndices[ip]];
+ }
+
+ // setup Jacobian terms
+ real64 dControlEqn[NC+2+IS_THERMAL]{};
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [phaseIndices,
+ connRate,
+ phaseDens,
+ dPhaseDens,
+ phaseFrac,
+ dPhaseFrac,
+ compFrac,
+ dCompFrac_dCompDens,
+ &dControlEqn,
+ &useSurfaceConditions,
+ &iwelemRef] ( localIndex const )
+ {
+
+ stackArray1d< real64, NC > work( NC );
+ for( integer i= 0; i < phaseIndices.size(); ++i )
+ {
+ integer ip = phaseIndices[i];
+ bool const phaseExists = (phaseFrac[iwelemRef][0][ip] > 0);
+ // skip the rest of this function if phase ip is absent
+ if( phaseExists )
+ {
+
+ real64 const currentTotalRate = connRate[iwelemRef];
+
+ real64 const phaseDensInv = 1.0 / phaseDens[iwelemRef][0][ip];
+ real64 const phaseFracTimesPhaseDensInv = phaseFrac[iwelemRef][0][ip] * phaseDensInv;
+ real64 const dPhaseFracTimesPhaseDensInv_dPres = dPhaseFrac[iwelemRef][0][ip][Deriv::dP] * phaseDensInv
+ - dPhaseDens[iwelemRef][0][ip][Deriv::dP] * phaseFracTimesPhaseDensInv * phaseDensInv;
+
+ // divide the total mass/molar rate by the (phase density * phase fraction) to get the phase volumetric rate
+ dControlEqn[COFFSET_WJ::dP] += ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dPres;
+ dControlEqn[COFFSET_WJ::dQ] += phaseFracTimesPhaseDensInv;
+ if constexpr (IS_THERMAL )
+ {
+ real64 const dPhaseFracTimesPhaseDensInv_dTemp = dPhaseFrac[iwelemRef][0][ip][Deriv::dT] * phaseDensInv
+ - dPhaseDens[iwelemRef][0][ip][Deriv::dT] * phaseFracTimesPhaseDensInv * phaseDensInv;
+ dControlEqn[COFFSET_WJ::dT] += ( useSurfaceConditions == 0 ) * currentTotalRate * dPhaseFracTimesPhaseDensInv_dTemp;
+ }
+
+ for( integer ic = 0; ic < NC; ++ic )
+ {
+ real64 temp = -phaseFracTimesPhaseDensInv * dPhaseDens[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv;
+ temp += dPhaseFrac[iwelemRef][0][ip][Deriv::dC+ic] * phaseDensInv;
+ temp *= currentTotalRate;
+ dControlEqn[COFFSET_WJ::dC+ic] += temp;
+ }
+ }
+ }
+ applyChainRuleInPlace( NC, dCompFrac_dCompDens[iwelemRef], &dControlEqn[COFFSET_WJ::dC], work.data() );
+ } );
+
+ // add solver matrices
+ localRhs[eqnRowIndex] += controlEqn;
+ localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
+ dofColIndices,
+ dControlEqn,
+ COFFSET_WJ::nDer );
+ }
+ template< template< typename U > class T, typename U=VolumeRateConstraint >
+ static void assembleConstraintEquation( real64 const & time_n,
+ WellControls & wellControls,
+ T< VolumeRateConstraint > & constraint,
+ WellElementSubRegion const & subRegion,
+ string const & wellDofKey,
+ localIndex const & rankOffset,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // subRegion data
+
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >();
+ arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >();
+ arrayView3d< real64 const, compflow::USD_COMP_DC > const & dCompFrac_dCompDens = subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >();
+
+ // setup row/column indices for constraint equation
+ using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
+ using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >;
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ localIndex const eqnRowIndex = wellElemDofNumber[iwelemRef] + WJ_ROFFSET::CONTROL - rankOffset;
+ globalIndex dofColIndices[COFFSET_WJ::nDer]{};
+ for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic )
+ {
+ dofColIndices[ ic ] = wellElemDofNumber[iwelemRef] + ic;
+ }
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
+
+ arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & totalDens = fluidSeparator.totalDensity();
+ arrayView3d< real64 const, constitutive::multifluid::USD_FLUID_DC > const & dTotalDens = fluidSeparator.dTotalDensity();
+
+ // constraint data
+ real64 const & targetTotalVolRate = constraint.getConstraintValue( time_n );
+
+ // current constraint value
+ real64 const & currentTotalVolRate =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+
+ // residual
+ real64 controlEqn = currentTotalVolRate - targetTotalVolRate;
+
+ // setup Jacobian terms
+ real64 dControlEqn[NC+2+IS_THERMAL]{};
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [connRate,
+ totalDens,
+ dTotalDens,
+ compFrac,
+ dCompFrac_dCompDens,
+ &dControlEqn,
+ &useSurfaceConditions,
+ &iwelemRef] ( localIndex const )
+ {
+ stackArray1d< real64, NC > work( NC );
+
+ real64 const currentTotalRate = connRate[iwelemRef];
+
+ // compute the inverse of the total density and derivatives
+
+ real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0];
+
+ stackArray1d< real64, NC > dTotalDensInv_dCompDens( NC );
+ for( integer ic = 0; ic < NC; ++ic )
+ {
+ dTotalDensInv_dCompDens[ic] = -dTotalDens[iwelemRef][0][Deriv::dC+ic] * totalDensInv * totalDensInv;
+ }
+ applyChainRuleInPlace( NC, dCompFrac_dCompDens[iwelemRef], dTotalDensInv_dCompDens, work.data() );
+
+ // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate
+
+ // Compute derivatives dP dT
+ real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv;
+ dControlEqn[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 ) * currentTotalRate * dTotalDensInv_dPres;
+ if constexpr ( IS_THERMAL )
+ {
+ dControlEqn[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv;
+ }
+
+ dControlEqn[COFFSET_WJ::dQ] = totalDensInv;
+ for( integer ic = 0; ic < NC; ++ic )
+ {
+ dControlEqn[COFFSET_WJ::dC+ic] = currentTotalRate * dTotalDensInv_dCompDens[ic];
+ }
+
+ } );
+
+ // add solver matrices
+ localRhs[eqnRowIndex] += controlEqn;
+ localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
+ dofColIndices,
+ dControlEqn,
+ COFFSET_WJ::nDer );
+ }
+ template< template< typename U > class T, typename U=MassRateConstraint >
+ static void assembleConstraintEquation( real64 const & time_n,
+ WellControls & wellControls,
+ T< MassRateConstraint > & constraint,
+ WellElementSubRegion const & subRegion,
+ string const & wellDofKey,
+ localIndex const & rankOffset,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // subRegion data
+
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & connRate = subRegion.getField< fields::well::mixtureConnectionRate >();
+ arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< fields::well::globalCompFraction >();
+ arrayView3d< real64 const, compflow::USD_COMP_DC > const & dCompFrac_dCompDens = subRegion.getField< fields::well::dGlobalCompFraction_dGlobalCompDensity >();
+
+ // setup row/column indices for constraint equation
+ using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
+ using WJ_ROFFSET = compositionalMultiphaseWellKernels::RowOffset_WellJac< NC, IS_THERMAL >;
+ using Deriv = constitutive::multifluid::DerivativeOffset;
+
+ localIndex const eqnRowIndex = wellElemDofNumber[iwelemRef] + WJ_ROFFSET::CONTROL - rankOffset;
+ globalIndex dofColIndices[COFFSET_WJ::nDer]{};
+ for( integer ic = 0; ic < COFFSET_WJ::nDer; ++ic )
+ {
+ dofColIndices[ ic ] = wellElemDofNumber[iwelemRef] + ic;
+ }
+
+ // fluid data
+ constitutive::MultiFluidBase & fluidSeparator = wellControls.getMultiFluidSeparator();
+ arrayView2d< real64 const, constitutive::multifluid::USD_FLUID > const & totalDens = fluidSeparator.totalDensity();
+ arrayView3d< real64 const, constitutive::multifluid::USD_FLUID_DC > const & dTotalDens = fluidSeparator.dTotalDensity();
+
+ // constraint data
+ real64 const & targetMassRate = constraint.getConstraintValue( time_n );
+
+ // current constraint value
+ real64 const & massDensity =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() );
+
+ // fix to use stored massrate
+ real64 const & currentTotalVolRate =
+ wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+
+ // residual
+ real64 controlEqn = massDensity*currentTotalVolRate - targetMassRate;
+
+ // setup Jacobian terms
+ real64 dControlEqn[NC+2+IS_THERMAL]{};
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [connRate,
+ massDensity,
+ totalDens,
+ dTotalDens,
+ compFrac,
+ dCompFrac_dCompDens,
+ &dControlEqn,
+ &useSurfaceConditions,
+ &iwelemRef] ( localIndex const )
+ {
+ stackArray1d< real64, NC > work( NC );
+
+ real64 const currentTotalRate = connRate[iwelemRef];
+
+ // compute the inverse of the total density and derivatives
+
+ real64 const totalDensInv = 1.0 / totalDens[iwelemRef][0];
+
+ stackArray1d< real64, NC > dTotalDensInv_dCompDens( NC );
+ for( integer ic = 0; ic < NC; ++ic )
+ {
+ dTotalDensInv_dCompDens[ic] = -dTotalDens[iwelemRef][0][Deriv::dC+ic] * totalDensInv * totalDensInv;
+ }
+ applyChainRuleInPlace( NC, dCompFrac_dCompDens[iwelemRef], dTotalDensInv_dCompDens, work.data() );
+
+ // Step 2.2: divide the total mass/molar rate by the total density to get the total volumetric rate
+
+ // Compute derivatives dP dT
+ real64 const dTotalDensInv_dPres = -dTotalDens[iwelemRef][0][Deriv::dP] * totalDensInv * totalDensInv;
+ dControlEqn[COFFSET_WJ::dP] = ( useSurfaceConditions == 0 )*massDensity * currentTotalRate * dTotalDensInv_dPres;
+ if constexpr ( IS_THERMAL )
+ {
+ dControlEqn[COFFSET_WJ::dT] = ( useSurfaceConditions == 0 ) * massDensity* currentTotalRate * -dTotalDens[iwelemRef][0][Deriv::dT] * totalDensInv * totalDensInv;
+ }
+
+ dControlEqn[COFFSET_WJ::dQ] = massDensity*totalDensInv;
+ for( integer ic = 0; ic < NC; ++ic )
+ {
+ dControlEqn[COFFSET_WJ::dC+ic] = massDensity* currentTotalRate * dTotalDensInv_dCompDens[ic];
+ }
+
+ } );
+
+ // add solver matrices
+ localRhs[eqnRowIndex] += controlEqn;
+ localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
+ dofColIndices,
+ dControlEqn,
+ COFFSET_WJ::nDer );
+ }
+};
+
+
+} // end namespace wellConstraintKernels
+
+} // end namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINTKERNELS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp
index ee04ffa8c73..5c2d4589705 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp
@@ -37,19 +37,19 @@ GEOS_HOST_DEVICE
inline
void
ControlEquationHelper::
- switchControl( bool const isProducer,
- WellControls::Control const & inputControl,
- WellControls::Control const & currentControl,
- integer const phasePhaseIndex,
- real64 const & targetBHP,
- real64 const & targetPhaseRate,
- real64 const & targetTotalRate,
- real64 const & targetMassRate,
- real64 const & currentBHP,
- arrayView1d< real64 const > const & currentPhaseVolRate,
- real64 const & currentTotalVolRate,
- real64 const & currentMassRate,
- WellControls::Control & newControl )
+ selectLimitingConstraint( bool const isProducer,
+ WellControls::Control const & inputControl,
+ WellControls::Control const & currentControl,
+ integer const phasePhaseIndex,
+ real64 const & targetBHP,
+ real64 const & targetPhaseRate,
+ real64 const & targetTotalRate,
+ real64 const & targetMassRate,
+ real64 const & currentBHP,
+ arrayView1d< real64 const > const & currentPhaseVolRate,
+ real64 const & currentTotalVolRate,
+ real64 const & currentMassRate,
+ WellControls::Control & newControl )
{
// if isViable is true at the end of the following checks, no need to switch
bool controlIsViable = false;
@@ -140,6 +140,7 @@ ControlEquationHelper::
real64 const & targetPhaseRate,
real64 const & targetTotalRate,
real64 const & targetMassRate,
+ real64 const & targetValue,
real64 const & currentBHP,
arrayView1d< real64 const > const & dCurrentBHP,
arrayView1d< real64 const > const & currentPhaseVolRate,
@@ -152,7 +153,7 @@ ControlEquationHelper::
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
-
+ GEOS_UNUSED_VAR( targetValue ); // tjb keeping this around if needed to compare with old constraint eqn jacgen
using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
using Deriv = multifluid::DerivativeOffset;
@@ -300,11 +301,6 @@ void
PressureRelationKernel::
launch( localIndex const size,
globalIndex const rankOffset,
- bool const isLocallyOwned,
- localIndex const iwelemControl,
- integer const targetPhaseIndex,
- WellControls const & wellControls,
- real64 const & time,
arrayView1d< integer const > const elemStatus,
arrayView1d< globalIndex const > const & wellElemDofNumber,
arrayView1d< real64 const > const & wellElemGravCoef,
@@ -317,36 +313,6 @@ PressureRelationKernel::
arrayView1d< real64 > const & localRhs )
{
using COFFSET_WJ = compositionalMultiphaseWellKernels::ColOffset_WellJac< NC, IS_THERMAL >;
- // static well control data
- bool const isProducer = wellControls.isProducer();
- WellControls::Control const currentControl = wellControls.getControl();
- WellControls::Control const inputControl = wellControls.getInputControl();
- real64 const targetBHP = wellControls.getTargetBHP( time );
- real64 const targetTotalRate = wellControls.getTargetTotalRate( time );
- real64 const targetPhaseRate = wellControls.getTargetPhaseRate( time );
- real64 const targetMassRate = wellControls.getTargetMassRate( time );
-
- // dynamic well control data
- real64 const & currentBHP =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentBHPString() );
- arrayView1d< real64 const > const & dCurrentBHP =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentBHPString() );
-
- arrayView1d< real64 const > const & currentPhaseVolRate =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() );
- arrayView2d< real64 const > const & dCurrentPhaseVolRate =
- wellControls.getReference< array2d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentPhaseVolRateString() );
-
- real64 const & currentTotalVolRate =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentTotalVolRateString() );
- arrayView1d< real64 const > const & dCurrentTotalVolRate =
- wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::dCurrentTotalVolRateString() );
-
- real64 const & currentMassRate =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::currentMassRateString() );
-
- real64 const & massDensity =
- wellControls.getReference< real64 >( CompositionalMultiphaseWell::viewKeyStruct::massDensityString() );
RAJA::ReduceMax< parallelDeviceReduce, localIndex > switchControl( 0 );
@@ -360,48 +326,7 @@ PressureRelationKernel::
localIndex const iwelemNext = nextWellElemIndex[iwelem];
- if( iwelemNext < 0 && isLocallyOwned ) // if iwelemNext < 0, form control equation
- {
-
- WellControls::Control newControl = currentControl;
- ControlEquationHelper::switchControl( isProducer,
- inputControl,
- currentControl,
- targetPhaseIndex,
- targetBHP,
- targetPhaseRate,
- targetTotalRate,
- targetMassRate,
- currentBHP,
- currentPhaseVolRate,
- currentTotalVolRate,
- currentMassRate,
- newControl );
- if( currentControl != newControl )
- {
- switchControl.max( 1 );
- }
- ControlEquationHelper::compute< NC, IS_THERMAL >( rankOffset,
- newControl,
- targetPhaseIndex,
- targetBHP,
- targetPhaseRate,
- targetTotalRate,
- targetMassRate,
- currentBHP,
- dCurrentBHP,
- currentPhaseVolRate,
- dCurrentPhaseVolRate,
- currentTotalVolRate,
- dCurrentTotalVolRate,
- massDensity,
- wellElemDofNumber[iwelemControl],
- localMatrix,
- localRhs );
- // TODO: for consistency, we should assemble here, not in compute...
-
- }
- else if( iwelemNext >= 0 ) // if iwelemNext >= 0, form momentum equation
+ if( iwelemNext >= 0 ) // if iwelemNext >= 0, form momentum equation
{
real64 localPresRel = 0;
@@ -455,11 +380,6 @@ PressureRelationKernel::
void PressureRelationKernel:: \
launch< NC, IS_THERMAL >( localIndex const size, \
globalIndex const rankOffset, \
- bool const isLocallyOwned, \
- localIndex const iwelemControl, \
- integer const targetPhaseIndex, \
- WellControls const & wellControls, \
- real64 const & time, \
arrayView1d< integer const > const elemStatus, \
arrayView1d< globalIndex const > const & wellElemDofNumber, \
arrayView1d< real64 const > const & wellElemGravCoef, \
@@ -716,62 +636,74 @@ CompDensInitializationKernel::
void
RateInitializationKernel::
launch( localIndex const subRegionSize,
- integer const targetPhaseIndex,
WellControls const & wellControls,
real64 const & time,
arrayView3d< real64 const, multifluid::USD_PHASE > const & phaseDens,
arrayView2d< real64 const, multifluid::USD_FLUID > const & totalDens,
arrayView1d< real64 > const & connRate )
{
- WellControls::Control const control = wellControls.getControl();
- bool const isProducer = wellControls.isProducer();
- real64 const targetTotalRate = wellControls.getTargetTotalRate( time );
- real64 const targetPhaseRate = wellControls.getTargetPhaseRate( time );
- real64 const targetMassRate = wellControls.getTargetMassRate( time );
-
- // Estimate the connection rates
- forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ if( wellControls.isProducer() )
{
- if( control == WellControls::Control::BHP )
+ std::vector< WellConstraintBase * > const constraints = wellControls.getProdRateConstraints();
+ // Use first rate constraint to set initial connection rates
+ real64 const constraintVal = constraints[0]->getConstraintValue( time );
+ ConstraintTypeId const controlType = constraints[0]->getControl();
+ if( controlType == ConstraintTypeId::PHASEVOLRATE )
{
- // if BHP constraint set rate below the absolute max rate
- // with the appropriate sign (negative for prod, positive for inj)
- if( isProducer )
+ integer const targetPhaseIndex = wellControls.getConstraintPhaseIndex();
+
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
{
- connRate[iwelem] = LvArray::math::max( 0.1 * targetPhaseRate * phaseDens[iwelem][0][targetPhaseIndex], -1e3 );
- }
- else
+ connRate[iwelem] = LvArray::math::max( 0.1 * constraintVal * phaseDens[iwelem][0][targetPhaseIndex], -1e3 );
+ } );
+ }
+ else if( controlType == ConstraintTypeId::TOTALVOLRATE )
+ {
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
{
- if( isZero( targetMassRate ) )
- {
- connRate[iwelem] = LvArray::math::min( 0.1 * targetTotalRate * totalDens[iwelem][0], 1e3 );
- }
- else
- {
- connRate[iwelem] = targetMassRate;
- }
-
- }
+ connRate[iwelem] = LvArray::math::max( 0.1 * constraintVal * totalDens[iwelem][0], -1e3 );
+ } );
}
- else if( control == WellControls::Control::MASSRATE )
+ else if( controlType == ConstraintTypeId::MASSRATE )
{
- connRate[iwelem] = targetMassRate;
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ connRate[iwelem] = constraintVal;
+ } );
}
- else
+ }
+ else
+ {
+ std::vector< WellConstraintBase * > const constraints = wellControls.getInjRateConstraints();
+ // Use first rate constraint to set initial connection rates
+ real64 const constraintVal = constraints[0]->getConstraintValue( time );
+ ConstraintTypeId const controlType = constraints[0]->getControl();
+ if( controlType == ConstraintTypeId::PHASEVOLRATE )
{
- if( isProducer )
+ integer const targetPhaseIndex = wellControls.getConstraintPhaseIndex();
+
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
{
- connRate[iwelem] = targetPhaseRate * phaseDens[iwelem][0][targetPhaseIndex];
- }
- else
+ connRate[iwelem] = LvArray::math::max( 0.1 * constraintVal * phaseDens[iwelem][0][targetPhaseIndex], 1e3 );
+ } );
+ }
+ else if( controlType == ConstraintTypeId::TOTALVOLRATE )
+ {
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
{
- connRate[iwelem] = targetTotalRate * totalDens[iwelem][0];
- }
+ connRate[iwelem] = constraintVal * totalDens[iwelem][0];
+ } );
}
- } );
+ else if( controlType == ConstraintTypeId::MASSRATE )
+ {
+ forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
+ {
+ connRate[iwelem] = constraintVal;
+ } );
+ }
+ }
}
-
} // end namespace compositionalMultiphaseWellKernels
} // end namespace geos
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp
index a8123abbb12..b01d8adf0ab 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp
@@ -40,6 +40,7 @@
#include "physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWellFields.hpp"
#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
#include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
namespace geos
{
@@ -134,19 +135,19 @@ struct ControlEquationHelper
inline
static
void
- switchControl( bool const isProducer,
- WellControls::Control const & inputControl,
- WellControls::Control const & currentControl,
- integer const phasePhaseIndex,
- real64 const & targetBHP,
- real64 const & targetPhaseRate,
- real64 const & targetTotalRate,
- real64 const & targetMassRate,
- real64 const & currentBHP,
- arrayView1d< real64 const > const & currentPhaseVolRate,
- real64 const & currentTotalVolRate,
- real64 const & currentMassRate,
- WellControls::Control & newControl );
+ selectLimitingConstraint( bool const isProducer,
+ WellControls::Control const & inputControl,
+ WellControls::Control const & currentControl,
+ integer const phasePhaseIndex,
+ real64 const & targetBHP,
+ real64 const & targetPhaseRate,
+ real64 const & targetTotalRate,
+ real64 const & targetMassRate,
+ real64 const & currentBHP,
+ arrayView1d< real64 const > const & currentPhaseVolRate,
+ real64 const & currentTotalVolRate,
+ real64 const & currentMassRate,
+ WellControls::Control & newControl );
template< integer NC, integer IS_THERMAL >
GEOS_HOST_DEVICE
@@ -160,6 +161,7 @@ struct ControlEquationHelper
real64 const & targetTotalRate,
real64 const & targetMassRate,
real64 const & currentBHP,
+ real64 const & targetValue,
arrayView1d< real64 const > const & dCurrentBHP,
arrayView1d< real64 const > const & currentPhaseVolRate,
arrayView2d< real64 const > const & dCurrentPhaseVolRate,
@@ -200,11 +202,6 @@ struct PressureRelationKernel
static void
launch( localIndex const size,
globalIndex const rankOffset,
- bool const isLocallyOwned,
- localIndex const iwelemControl,
- integer const targetPhaseIndex,
- WellControls const & wellControls,
- real64 const & time,
arrayView1d< integer const > const elemStatus,
arrayView1d< globalIndex const > const & wellElemDofNumber,
arrayView1d< real64 const > const & wellElemGravCoef,
@@ -323,7 +320,6 @@ struct RateInitializationKernel
static void
launch( localIndex const subRegionSize,
- integer const targetPhaseIndex,
WellControls const & wellControls,
real64 const & currentTime,
arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const & phaseDens,
@@ -505,7 +501,6 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
arrayView1d< localIndex const > const & ghostRank,
integer const numComp,
integer const numDof,
- integer const targetPhaseIndex,
WellElementSubRegion const & subRegion,
constitutive::MultiFluidBase const & fluid,
WellControls const & wellControls,
@@ -519,20 +514,41 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
minNormalizer ),
m_numComp( numComp ),
m_numDof( numDof ),
- m_targetPhaseIndex( targetPhaseIndex ),
m_dt( dt ),
m_isLocallyOwned( subRegion.isLocallyOwned() ),
m_iwelemControl( subRegion.getTopWellElementIndex() ),
m_isProducer( wellControls.isProducer() ),
m_currentControl( wellControls.getControl() ),
- m_targetBHP( wellControls.getTargetBHP( time ) ),
- m_targetTotalRate( wellControls.getTargetTotalRate( time ) ),
- m_targetPhaseRate( wellControls.getTargetPhaseRate( time ) ),
- m_targetMassRate( wellControls.getTargetMassRate( time ) ),
m_volume( subRegion.getElementVolume() ),
m_phaseDens_n( fluid.phaseDensity_n() ),
m_totalDens_n( fluid.totalDensity_n() )
- {}
+ {
+ if( m_isProducer )
+ {
+ m_targetBHP = wellControls.getMinBHPConstraint()->getConstraintValue( time );
+ // Note this assumes that there is only one rate constraint
+ // This is a normalizer for the balance equations. The normalizaer should be the current rate not the constraint value!!
+ // This is one of the reasons for restricting constraint type for a production well
+ // another pr will remove fix this (so the cause for difference results is isolated to one change)
+ m_targetPhaseIndex = wellControls.getConstraintPhaseIndex( );
+ m_constraintValue = wellControls.getProdRateConstraints()[0]->getConstraintValue( time );
+
+ }
+ else
+ {
+ m_targetBHP = wellControls.getMaxBHPConstraint()->getConstraintValue( time );
+
+ // Note this assumes that there is only one rate constraint
+ // This is a normalizer for the balance equations. The normalizaer should be the current rate not the constraint value!!
+ // This is one of the reasons for restricting constraint type for a production well
+ // another pr will remove fix this (so the cause for difference results is isolated to one change)
+ m_targetPhaseIndex = -1;
+ m_constraintValue = wellControls.getInjRateConstraints()[0]->getConstraintValue( time );
+
+ }
+
+
+ }
GEOS_HOST_DEVICE
virtual void computeLinf( localIndex const iwelem,
@@ -561,17 +577,17 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
else if( m_currentControl == WellControls::Control::TOTALVOLRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetTotalRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
else if( m_currentControl == WellControls::Control::PHASEVOLRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetPhaseRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
else if( m_currentControl == WellControls::Control::MASSRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
}
// for the pressure difference equation, always normalize by the BHP
@@ -586,18 +602,18 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
if( m_isProducer ) // only PHASEVOLRATE is supported for now
{
// the residual is in mass units
- normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex];
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex];
}
else // Type::INJECTOR, only TOTALVOLRATE is supported for now
{
if( m_currentControl == WellControls::Control::MASSRATE )
{
- normalizer = m_dt * LvArray::math::abs( m_targetMassRate );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue );
}
else
{
// the residual is in mass units
- normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0];
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_totalDens_n[iwelem][0];
}
}
@@ -611,17 +627,17 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
if( m_isProducer ) // only PHASEVOLRATE is supported for now
{
// the residual is in volume units
- normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue );
}
else // Type::INJECTOR, only TOTALVOLRATE is supported for now
{
if( m_currentControl == WellControls::Control::MASSRATE )
{
- normalizer = m_dt * LvArray::math::abs( m_targetMassRate/ m_totalDens_n[iwelem][0] );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue/ m_totalDens_n[iwelem][0] );
}
else
{
- normalizer = m_dt * LvArray::math::abs( m_targetTotalRate );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue );
}
}
@@ -658,7 +674,7 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
integer const m_numDof;
/// Index of the target phase
- integer const m_targetPhaseIndex;
+ integer m_targetPhaseIndex;
/// Time step size
real64 const m_dt;
@@ -674,10 +690,9 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
/// Controls
WellControls::Control const m_currentControl;
- real64 const m_targetBHP;
- real64 const m_targetTotalRate;
- real64 const m_targetPhaseRate;
- real64 const m_targetMassRate;
+ real64 m_constraintValue;
+ real64 m_targetBHP;
+
/// View on the volume
arrayView1d< real64 const > const m_volume;
@@ -700,7 +715,6 @@ class ResidualNormKernelFactory
* @tparam POLICY the policy used in the RAJA kernel
* @param[in] numComp number of fluid components
* @param[in] numDof number of dofs per well element
- * @param[in] targetPhaseIndex the index of the target phase (for phase volume control)
* @param[in] rankOffset the offset of my MPI rank
* @param[in] dofKey the string key to retrieve the degress of freedom numbers
* @param[in] localResidual the residual vector on my MPI rank
@@ -715,7 +729,6 @@ class ResidualNormKernelFactory
static void
createAndLaunch( integer const numComp,
integer const numDof,
- integer const targetPhaseIndex,
globalIndex const rankOffset,
string const & dofKey,
arrayView1d< real64 const > const & localResidual,
@@ -731,7 +744,7 @@ class ResidualNormKernelFactory
arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
ResidualNormKernel kernel( rankOffset, localResidual, dofNumber, ghostRank,
- numComp, numDof, targetPhaseIndex, subRegion, fluid, wellControls, time, dt, minNormalizer );
+ numComp, numDof, subRegion, fluid, wellControls, time, dt, minNormalizer );
ResidualNormKernel::launchLinf< POLICY >( subRegion.size(), kernel, residualNorm );
}
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp
index 18a48ee1e63..e8862990a2d 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/PerforationFluxKernels.hpp
@@ -569,7 +569,7 @@ class PerforationFluxKernelFactory
string const flowSolverName,
PerforationData * const perforationData,
ElementSubRegionBase const & subRegion,
- ElementRegionManager & elemManager,
+ ElementRegionManager const & elemManager,
bool const isInjector,
bool const isCrossflowEnabled )
{
@@ -848,7 +848,7 @@ class PerforationFluxKernelFactory
PerforationData * const perforationData,
ElementSubRegionBase const & subRegion,
MultiFluidBase const & fluid,
- ElementRegionManager & elemManager,
+ ElementRegionManager const & elemManager,
bool const isInjector,
bool const isCrossflowEnabled )
{
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellConstraintKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellConstraintKernels.hpp
new file mode 100644
index 00000000000..a7f7af725ce
--- /dev/null
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellConstraintKernels.hpp
@@ -0,0 +1,195 @@
+/*
+ * ------------------------------------------------------------------------------------------------------------
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
+ * Copyright (c) 2018-2024 TotalEnergies
+ * 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 SinglePhaseWellConstraintKernels.hpp
+ */
+
+#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELLCONSTRAINTKERNELS_HPP
+#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELLCONSTRAINTKERNELS_HPP
+
+#include "codingUtilities/Utilities.hpp"
+#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
+#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp"
+
+
+#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp"
+
+
+namespace geos
+{
+
+namespace singlePhaseWellConstraintKernels
+{
+
+/******************************** ControlEquationHelper ********************************/
+
+
+template< integer IS_THERMAL >
+struct ConstraintHelper
+{
+ static void assembleConstraintEquation( real64 const & time_n,
+ WellControls & wellControls,
+ BHPConstraint & constraint,
+ WellElementSubRegion const & subRegion,
+ string const & wellDofKey,
+ localIndex const & rankOffset,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // subRegion data
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+ arrayView1d< real64 const > const & pres = subRegion.getField< fields::well::pressure >();
+
+ constitutive::SingleFluidBase & fluidSeparator = wellControls.getSingleFluidSeparator();
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & density = fluidSeparator.density();
+ arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const & dDensity = fluidSeparator.dDensity();
+
+ arrayView1d< real64 const > const wellElemGravCoef = subRegion.getField< fields::well::gravityCoefficient >();
+
+ // setup row/column indices for constraint equation
+ using ROFFSET_WJ = singlePhaseWellKernels::RowOffset_WellJac< IS_THERMAL >;
+ using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >;
+ using Deriv = constitutive::singlefluid::DerivativeOffsetC< IS_THERMAL >;
+
+ localIndex const eqnRowIndex = wellElemDofNumber[iwelemRef] + ROFFSET_WJ::CONTROL - rankOffset;
+ globalIndex dofColIndices[COFFSET_WJ::nDer]{};
+ for( integer i = 0; i < COFFSET_WJ::nDer; ++i )
+ {
+ dofColIndices[ i ] = wellElemDofNumber[iwelemRef] + i;
+ }
+ // constraint data
+ real64 const & targetBHP = constraint.getConstraintValue( time_n );
+ real64 const & refGravCoef = constraint.getReferenceGravityCoef();
+
+ // current constraint value
+ real64 const & currentBHP =
+ wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() );
+
+ // residual
+ real64 controlEqn = currentBHP - targetBHP;
+
+ // setup Jacobian terms
+ real64 dControlEqn[2+IS_THERMAL]{};
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [pres,
+ density,
+ dDensity,
+ wellElemGravCoef,
+ &dControlEqn,
+ &iwelemRef,
+ &refGravCoef] ( localIndex const )
+ {
+ real64 const diffGravCoef = refGravCoef - wellElemGravCoef[iwelemRef];
+ dControlEqn[COFFSET_WJ::dP] = 1.0 + dDensity[iwelemRef][0][Deriv::dP] *diffGravCoef;
+ if constexpr ( IS_THERMAL )
+ {
+ dControlEqn[COFFSET_WJ::dT] = dDensity[iwelemRef][0][Deriv::dT] * diffGravCoef;
+ }
+ } );
+
+ // add solver matrices
+ localRhs[eqnRowIndex] += controlEqn;
+ localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
+ dofColIndices,
+ dControlEqn,
+ COFFSET_WJ::nDer );
+ }
+ template< template< typename U > class T, typename U=VolumeRateConstraint >
+ static void assembleConstraintEquation( real64 const & time_n,
+ WellControls & wellControls,
+ T< VolumeRateConstraint > & constraint,
+ WellElementSubRegion const & subRegion,
+ string const & wellDofKey,
+ localIndex const & rankOffset,
+ CRSMatrixView< real64, globalIndex const > const & localMatrix,
+ arrayView1d< real64 > const & localRhs )
+ {
+ // subRegion data
+
+ localIndex const iwelemRef = subRegion.getTopWellElementIndex();
+ arrayView1d< globalIndex const > const & wellElemDofNumber = subRegion.getReference< array1d< globalIndex > >( wellDofKey );
+
+
+ // setup row/column indices for constraint equation
+ using ROFFSET_WJ = singlePhaseWellKernels::RowOffset_WellJac< IS_THERMAL >;
+ using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >;
+ using Deriv = constitutive::singlefluid::DerivativeOffsetC< IS_THERMAL >;
+
+ localIndex const eqnRowIndex = wellElemDofNumber[iwelemRef] + ROFFSET_WJ::CONTROL - rankOffset;
+ globalIndex dofColIndices[COFFSET_WJ::nDer]{};
+ for( integer i = 0; i < COFFSET_WJ::nDer; ++i )
+ {
+ dofColIndices[ i ] = wellElemDofNumber[iwelemRef] + i;
+ }
+
+ // fluid data
+ constitutive::SingleFluidBase & fluidSeparator = wellControls.getSingleFluidSeparator();
+ arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & density = fluidSeparator.density();
+ arrayView3d< real64 const, constitutive::singlefluid::USD_FLUID_DER > const & dDensity = fluidSeparator.dDensity();
+
+ // constraint data
+ real64 const & targetVolRate = constraint.getConstraintValue( time_n );
+
+ // current constraint value
+ real64 & currentVolRate =
+ wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() );
+
+ integer const useSurfaceConditions = wellControls.useSurfaceConditions();
+
+ // residual
+ real64 controlEqn = currentVolRate - targetVolRate;
+
+ // setup Jacobian terms
+ real64 dControlEqn[2+IS_THERMAL]{};
+
+ // bring everything back to host, capture the scalars by reference
+ forAll< serialPolicy >( 1, [currentVolRate,
+ density,
+ dDensity,
+ &dControlEqn,
+ &useSurfaceConditions,
+ &iwelemRef] ( localIndex const )
+ {
+ // compute the inverse of the total density and derivatives
+ real64 const densInv = 1.0 / density[iwelemRef][0];
+
+ dControlEqn[COFFSET_WJ::dP] = -( useSurfaceConditions == 0 ) * dDensity[iwelemRef][0][Deriv::dP] * currentVolRate * densInv;
+ dControlEqn[COFFSET_WJ::dQ] = densInv;
+ if constexpr ( IS_THERMAL )
+ {
+ dControlEqn[COFFSET_WJ::dT] = -( useSurfaceConditions == 0 ) * dDensity[iwelemRef][0][Deriv::dT] * currentVolRate * densInv;
+ }
+
+ } );
+
+ // add solver matrices
+ localRhs[eqnRowIndex] += controlEqn;
+ localMatrix.addToRowBinarySearchUnsorted< serialAtomic >( eqnRowIndex,
+ dofColIndices,
+ dControlEqn,
+ COFFSET_WJ::nDer );
+ }
+};
+
+} // end namespace wellConstraintKernels
+
+} // end namespace geos
+
+#endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_WELLCONSTRAINTKERNELS_HPP
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp
index ddd707cf9b1..35bb78a54c4 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp
@@ -23,6 +23,7 @@
#include "physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp"
#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidLayouts.hpp"
+
namespace geos
{
@@ -262,14 +263,10 @@ FluxKernel::
#define INST_PressureRelationKernel( IS_THERMAL ) \
template \
- localIndex \
+ void \
PressureRelationKernel:: \
launch< IS_THERMAL >( localIndex const size, \
globalIndex const rankOffset, \
- bool const isLocallyOwned, \
- localIndex const iwelemControl, \
- WellControls const & wellControls, \
- real64 const & timeAtEndOfStep, \
arrayView1d< globalIndex const > const & wellElemDofNumber, \
arrayView1d< real64 const > const & wellElemGravCoef, \
arrayView1d< localIndex const > const & nextWellElemIndex, \
@@ -283,14 +280,10 @@ INST_PressureRelationKernel( 0 );
INST_PressureRelationKernel( 1 );
template< integer IS_THERMAL >
-localIndex
+void
PressureRelationKernel::
launch( localIndex const size,
globalIndex const rankOffset,
- bool const isLocallyOwned,
- localIndex const iwelemControl,
- WellControls const & wellControls,
- real64 const & time,
arrayView1d< globalIndex const > const & wellElemDofNumber,
arrayView1d< real64 const > const & wellElemGravCoef,
arrayView1d< localIndex const > const & nextWellElemIndex,
@@ -303,23 +296,6 @@ PressureRelationKernel::
using Deriv = constitutive::singlefluid::DerivativeOffset;
using COFFSET_WJ = singlePhaseWellKernels::ColOffset_WellJac< IS_THERMAL >;
// static well control data
- bool const isProducer = wellControls.isProducer();
- WellControls::Control const currentControl = wellControls.getControl();
- real64 const targetBHP = wellControls.getTargetBHP( time );
- real64 const targetRate = wellControls.getTargetTotalRate( time );
-
- // dynamic well control data
- real64 const & currentBHP =
- wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentBHPString() );
- arrayView1d< real64 const > const & dCurrentBHP =
- wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentBHPString() );
-
- real64 const & currentVolRate =
- wellControls.getReference< real64 >( SinglePhaseWell::viewKeyStruct::currentVolRateString() );
- arrayView1d< real64 const > const & dCurrentVolRate =
- wellControls.getReference< array1d< real64 > >( SinglePhaseWell::viewKeyStruct::dCurrentVolRateString() );
-
- RAJA::ReduceMax< parallelDeviceReduce, localIndex > switchControl( 0 );
// loop over the well elements to compute the pressure relations between well elements
forAll< parallelDevicePolicy<> >( size, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
@@ -327,34 +303,7 @@ PressureRelationKernel::
localIndex const iwelemNext = nextWellElemIndex[iwelem];
- if( iwelemNext < 0 && isLocallyOwned ) // if iwelemNext < 0, form control equation
- {
- WellControls::Control newControl = currentControl;
- ControlEquationHelper::switchControl( isProducer,
- currentControl,
- targetBHP,
- targetRate,
- currentBHP,
- currentVolRate,
- newControl );
- if( currentControl != newControl )
- {
- switchControl.max( 1 );
- }
-
- ControlEquationHelper::compute< IS_THERMAL >( rankOffset,
- newControl,
- targetBHP,
- targetRate,
- currentBHP,
- dCurrentBHP,
- currentVolRate,
- dCurrentVolRate,
- wellElemDofNumber[iwelemControl],
- localMatrix,
- localRhs );
- }
- else if( iwelemNext >= 0 ) // if iwelemNext >= 0, form momentum equation
+ if( iwelemNext >= 0 ) // if iwelemNext >= 0, form momentum equation
{
// local working variables and arrays
@@ -406,7 +355,6 @@ PressureRelationKernel::
}
}
} );
- return switchControl.get();
}
/******************************** AccumulationKernel ********************************/
@@ -599,10 +547,22 @@ RateInitializationKernel::
arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > const & wellElemDens,
arrayView1d< real64 > const & connRate )
{
- real64 const targetRate = wellControls.getTargetTotalRate( currentTime );
+
WellControls::Control const control = wellControls.getControl();
bool const isProducer = wellControls.isProducer();
-
+ real64 constraintVal;
+ if( isProducer )
+ {
+ std::vector< WellConstraintBase * > const constraints = wellControls.getProdRateConstraints();
+ // Use first rate constraint to set initial connection rates
+ constraintVal = constraints[0]->getConstraintValue( currentTime );
+ }
+ else
+ {
+ std::vector< WellConstraintBase * > const constraints = wellControls.getInjRateConstraints();
+ // Use first rate constraint to set initial connection rates
+ constraintVal = constraints[0]->getConstraintValue( currentTime );;
+ }
// Estimate the connection rates
forAll< parallelDevicePolicy<> >( subRegionSize, [=] GEOS_HOST_DEVICE ( localIndex const iwelem )
{
@@ -612,16 +572,16 @@ RateInitializationKernel::
// with the appropriate sign (negative for prod, positive for inj)
if( isProducer )
{
- connRate[iwelem] = LvArray::math::max( 0.1 * targetRate * wellElemDens[iwelem][0], -1e3 );
+ connRate[iwelem] = LvArray::math::max( 0.1 * constraintVal * wellElemDens[iwelem][0], -1e3 );
}
else
{
- connRate[iwelem] = LvArray::math::min( 0.1 * targetRate * wellElemDens[iwelem][0], 1e3 );
+ connRate[iwelem] = LvArray::math::min( 0.1 * constraintVal * wellElemDens[iwelem][0], 1e3 );
}
}
else
{
- connRate[iwelem] = targetRate * wellElemDens[iwelem][0];
+ connRate[iwelem] = constraintVal * wellElemDens[iwelem][0];
}
} );
}
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp
index 5221162c73c..dcb8b61f9be 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp
@@ -20,18 +20,21 @@
#ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELLKERNELS_HPP
#define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_SINGLEPHASEWELLKERNELS_HPP
+#include "common/DataTypes.hpp"
+#include "common/GEOS_RAJA_Interface.hpp"
+#include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+
#include "constitutive/fluid/singlefluid/SingleFluidFields.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidLayouts.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidLayouts.hpp"
-#include "common/DataTypes.hpp"
-#include "common/GEOS_RAJA_Interface.hpp"
+
#include "mesh/ElementRegionManager.hpp"
#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp"
#include "physicsSolvers/fluidFlow/StencilAccessors.hpp"
#include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
#include "physicsSolvers/fluidFlow/wells/SinglePhaseWellFields.hpp"
-#include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+
#include "physicsSolvers/KernelLaunchSelectors.hpp"
namespace geos
@@ -185,13 +188,9 @@ struct PressureRelationKernel
using TAG = singlePhaseWellKernels::ElemTag;
template< integer IS_THERMAL >
- static localIndex
+ static void
launch( localIndex const size,
globalIndex const rankOffset,
- bool const isLocallyOwned,
- localIndex const iwelemControl,
- WellControls const & wellControls,
- real64 const & time,
arrayView1d< globalIndex const > const & wellElemDofNumber,
arrayView1d< real64 const > const & wellElemGravCoef,
arrayView1d< localIndex const > const & nextWellElemIndex,
@@ -811,12 +810,19 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
m_isLocallyOwned( subRegion.isLocallyOwned() ),
m_iwelemControl( subRegion.getTopWellElementIndex() ),
m_currentControl( wellControls.getControl() ),
- m_targetBHP( wellControls.getTargetBHP( time ) ),
- m_targetRate( wellControls.getTargetTotalRate( time ) ),
- m_targetMassRate( wellControls.getTargetMassRate( time ) ),
+ m_constraintValue ( wellControls.getCurrentConstraint()->getConstraintValue( time )),
m_volume( subRegion.getElementVolume() ),
m_density_n( fluid.density_n() )
- {}
+ {
+ if( wellControls.isProducer() )
+ {
+ m_targetBHP = wellControls.getMinBHPConstraint()->getConstraintValue( time );
+ }
+ else
+ {
+ m_targetBHP = wellControls.getMaxBHPConstraint()->getConstraintValue( time );
+ }
+ }
GEOS_HOST_DEVICE
virtual void computeLinf( localIndex const iwelem,
@@ -838,12 +844,12 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
else if( m_currentControl == WellControls::Control::TOTALVOLRATE )
{
// this residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
else if( m_currentControl == WellControls::Control::MASSRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
}
// for the pressure difference equation, always normalize by the BHP
@@ -856,7 +862,7 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
else // SinglePhaseWell::RowOffset::MASSBAL
{
// this residual entry is in mass units
- normalizer = m_dt * LvArray::math::abs( m_targetRate ) * m_density_n[iwelem][0];
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_density_n[iwelem][0];
// to make sure that everything still works well if the rate is zero, we add this check
normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_density_n[iwelem][0] );
@@ -894,9 +900,9 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
/// Controls
WellControls::Control const m_currentControl;
- real64 const m_targetBHP;
- real64 const m_targetRate;
- real64 const m_targetMassRate;
+ real64 const m_constraintValue;
+ real64 m_targetBHP;
+
/// View on the volume
arrayView1d< real64 const > const m_volume;
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp
index 54b7819e8bf..a949203843a 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp
@@ -22,6 +22,8 @@
#include "physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp"
#include "physicsSolvers/PhysicsSolverBaseKernels.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp"
+#include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
namespace geos
{
@@ -161,7 +163,7 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
arrayView1d< real64 const > const & localResidual,
arrayView1d< globalIndex const > const & dofNumber,
arrayView1d< localIndex const > const & ghostRank,
- integer const targetPhaseIndex,
+
WellElementSubRegion const & subRegion,
MultiFluidBase const & fluid,
WellControls const & wellControls,
@@ -174,22 +176,37 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
ghostRank,
minNormalizer ),
m_numPhases( fluid.numFluidPhases()),
- m_targetPhaseIndex( targetPhaseIndex ),
m_dt( dt ),
m_isLocallyOwned( subRegion.isLocallyOwned() ),
m_iwelemControl( subRegion.getTopWellElementIndex() ),
m_isProducer( wellControls.isProducer() ),
m_currentControl( wellControls.getControl() ),
- m_targetBHP( wellControls.getTargetBHP( time ) ),
- m_targetTotalRate( wellControls.getTargetTotalRate( time ) ),
- m_targetPhaseRate( wellControls.getTargetPhaseRate( time ) ),
- m_targetMassRate( wellControls.getTargetMassRate( time ) ),
+ m_constraintValue ( wellControls.getCurrentConstraint()->getConstraintValue( time )),
m_volume( subRegion.getElementVolume() ),
m_phaseDens_n( fluid.phaseDensity_n() ),
m_totalDens_n( fluid.totalDensity_n() ),
m_phaseVolFraction_n( subRegion.getField< fields::well::phaseVolumeFraction_n >()),
m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() )
- {}
+ {
+ if( m_isProducer )
+ {
+ // tjb This needs to be fixed should use current constraint rate for normalization
+ m_targetBHP = wellControls.getMinBHPConstraint()->getConstraintValue( time );
+ if( m_currentControl == WellControls::Control::PHASEVOLRATE )
+ {
+ m_targetPhaseIndex = wellControls.getConstraintPhaseIndex();
+ }
+ }
+ else
+ {
+ m_targetBHP = wellControls.getMaxBHPConstraint()->getConstraintValue( time );
+ if( m_currentControl == WellControls::Control::PHASEVOLRATE )
+ {
+ m_targetPhaseIndex = wellControls.getConstraintPhaseIndex();
+ }
+ }
+
+ }
GEOS_HOST_DEVICE
@@ -232,17 +249,17 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
else if( m_currentControl == WellControls::Control::TOTALVOLRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetTotalRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
else if( m_currentControl == WellControls::Control::PHASEVOLRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetPhaseRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
else if( m_currentControl == WellControls::Control::MASSRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
}
// for the pressure difference equation, always normalize by the BHP
@@ -257,18 +274,18 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
if( m_isProducer ) // only PHASEVOLRATE is supported for now
{
// the residual is in mass units
- normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex];
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex];
}
else // Type::INJECTOR, only TOTALVOLRATE is supported for now
{
if( m_currentControl == WellControls::Control::MASSRATE )
{
- normalizer = m_dt * LvArray::math::abs( m_targetMassRate );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue );
}
else
{
// the residual is in mass units
- normalizer = m_dt * LvArray::math::abs( m_targetTotalRate ) * m_totalDens_n[iwelem][0];
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_totalDens_n[iwelem][0];
}
}
@@ -282,17 +299,17 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
if( m_isProducer ) // only PHASEVOLRATE is supported for now
{
// the residual is in volume units
- normalizer = m_dt * LvArray::math::abs( m_targetPhaseRate );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue );
}
else // Type::INJECTOR, only TOTALVOLRATE is supported for now
{
if( m_currentControl == WellControls::Control::MASSRATE )
{
- normalizer = m_dt * LvArray::math::abs( m_targetMassRate/ m_totalDens_n[iwelem][0] );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue/ m_totalDens_n[iwelem][0] );
}
else
{
- normalizer = m_dt * LvArray::math::abs( m_targetTotalRate );
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue );
}
}
@@ -339,7 +356,7 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
integer const m_numPhases;
/// Index of the target phase
- integer const m_targetPhaseIndex;
+ integer m_targetPhaseIndex;
/// Time step size
real64 const m_dt;
@@ -355,10 +372,9 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
/// Controls
WellControls::Control const m_currentControl;
- real64 const m_targetBHP;
- real64 const m_targetTotalRate;
- real64 const m_targetPhaseRate;
- real64 const m_targetMassRate;
+ real64 const m_constraintValue;
+ real64 m_targetBHP;
+
/// View on the volume
arrayView1d< real64 const > const m_volume;
@@ -383,7 +399,6 @@ class ResidualNormKernelFactory
* @tparam POLICY the policy used in the RAJA kernel
* @param[in] numComp number of fluid components
* @param[in] numDof number of dofs per well element
- * @param[in] targetPhaseIndex the index of the target phase (for phase volume control)
* @param[in] rankOffset the offset of my MPI rank
* @param[in] dofKey the string key to retrieve the degress of freedom numbers
* @param[in] localResidual the residual vector on my MPI rank
@@ -397,7 +412,6 @@ class ResidualNormKernelFactory
template< typename POLICY >
static void
createAndLaunch( integer const numComp,
- integer const targetPhaseIndex,
globalIndex const rankOffset,
string const & dofKey,
arrayView1d< real64 const > const & localResidual,
@@ -418,7 +432,7 @@ class ResidualNormKernelFactory
arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
kernelType kernel( rankOffset, localResidual, dofNumber, ghostRank,
- targetPhaseIndex, subRegion, fluid, wellControls, time, dt, minNormalizer );
+ subRegion, fluid, wellControls, time, dt, minNormalizer );
kernelType::template launchLinf< POLICY >( subRegion.size(), kernel, residualNorm );
} );
}
@@ -645,8 +659,7 @@ class ElementBasedAssemblyKernelFactory
CRSMatrixView< real64, globalIndex const > const & localMatrix,
arrayView1d< real64 > const & localRhs )
{
- isothermalCompositionalMultiphaseBaseKernels::
- internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC )
+ isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC )
{
localIndex constexpr NUM_COMP = NC();
diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp
index f736826561c..b19ca90845d 100644
--- a/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp
+++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp
@@ -522,14 +522,21 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
m_iwelemControl( subRegion.getTopWellElementIndex() ),
m_isProducer( wellControls.isProducer() ),
m_currentControl( wellControls.getControl() ),
- m_targetBHP( wellControls.getTargetBHP( time ) ),
- m_targetRate( wellControls.getTargetTotalRate( time ) ),
- m_targetMassRate( wellControls.getTargetMassRate( time ) ),
+ m_constraintValue ( wellControls.getCurrentConstraint()->getConstraintValue( time )),
m_volume( subRegion.getElementVolume() ),
m_density_n( fluid.density_n() ),
m_internalEnergy_n( fluid.internalEnergy_n() )
- {}
+ {
+ if( wellControls.isProducer() )
+ {
+ m_targetBHP = wellControls.getMinBHPConstraint()->getConstraintValue( time );
+ }
+ else
+ {
+ m_targetBHP = wellControls.getMaxBHPConstraint()->getConstraintValue( time );
+ }
+ }
GEOS_HOST_DEVICE
@@ -568,12 +575,12 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
else if( m_currentControl == WellControls::Control::TOTALVOLRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
else if( m_currentControl == WellControls::Control::MASSRATE )
{
// the residual entry is in volume / time units
- normalizer = LvArray::math::max( LvArray::math::abs( m_targetMassRate ), m_minNormalizer );
+ normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
}
}
// for the pressure difference equation, always normalize by the BHP
@@ -587,7 +594,7 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
{
// this residual entry is in mass units
- normalizer = m_dt * LvArray::math::abs( m_targetRate ) * m_density_n[iwelem][0];
+ normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_density_n[iwelem][0];
// to make sure that everything still works well if the rate is zero, we add this check
normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_density_n[iwelem][0] );
@@ -640,9 +647,8 @@ class ResidualNormKernel : public physicsSolverBaseKernels::ResidualNormKernelBa
/// Controls
WellControls::Control const m_currentControl;
- real64 const m_targetBHP;
- real64 const m_targetRate;
- real64 const m_targetMassRate;
+ real64 const m_constraintValue;
+ real64 m_targetBHP;
/// View on the volume
arrayView1d< real64 const > const m_volume;
diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd
index e29fdc5fd0b..641e4b1ae98 100644
--- a/src/coreComponents/schema/schema.xsd
+++ b/src/coreComponents/schema/schema.xsd
@@ -222,18 +222,10 @@
-
-
-
-
-
-
-
-
@@ -1536,26 +1528,10 @@ stress - traction is applied to the faces as specified by the inner product of i
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1564,18 +1540,6 @@ stress - traction is applied to the faces as specified by the inner product of i
-
-
-
-
-
-
-
-
-
-
-
-
@@ -3532,7 +3496,44 @@ When set to `all` output both convergence & iteration information to a csv.-->
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3573,6 +3574,8 @@ Information output from lower logLevels is added with the desired log level
+
+
@@ -3589,6 +3592,17 @@ When set to `all` output both convergence & iteration information to a csv.-->
+
+
+
+
+
+
+
+
+
+
+
- Injector pressure at reference depth initialized as: (1+initialPressureCoefficient)*reservoirPressureAtClosestPerforation + density*g*( zRef - zPerf )
- Producer pressure at reference depth initialized as: (1-initialPressureCoefficient)*reservoirPressureAtClosestPerforation + density*g*( zRef - zPerf ) -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -3655,6 +3642,109 @@ See note on referenceReservoirRegion for reservoir condition options-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -4060,7 +4150,7 @@ Information output from lower logLevels is added with the desired log level
-
+
@@ -4089,7 +4179,7 @@ When set to `all` output both convergence & iteration information to a csv.-->
-
+
@@ -5358,7 +5448,44 @@ When set to `all` output both convergence & iteration information to a csv.-->
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -5387,6 +5514,8 @@ Information output from lower logLevels is added with the desired log level
+
+
diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other
index 33a2ec00f2c..a427cacdbd4 100644
--- a/src/coreComponents/schema/schema.xsd.other
+++ b/src/coreComponents/schema/schema.xsd.other
@@ -341,15 +341,11 @@
-
-
-
-
@@ -854,9 +850,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3423,7 +3439,7 @@
-
+
@@ -3451,7 +3467,7 @@
-
+
@@ -3470,11 +3486,11 @@
-
+
-
+
@@ -3484,7 +3500,7 @@
-
+
@@ -3494,11 +3510,11 @@
-
+
-
+
@@ -3508,7 +3524,7 @@
-
+
@@ -3518,7 +3534,7 @@
-
+
@@ -3528,7 +3544,7 @@
-
+
@@ -3552,7 +3568,7 @@
-
+
@@ -3570,7 +3586,7 @@
-
+
@@ -3582,7 +3598,7 @@
-
+
@@ -3594,7 +3610,7 @@
-
+
@@ -3602,11 +3618,11 @@
-
+
-
+
@@ -3629,7 +3645,7 @@
-
+
@@ -3655,7 +3671,7 @@
-
+
@@ -3676,7 +3692,7 @@
-
+
@@ -3706,7 +3722,7 @@
-
+
@@ -3720,7 +3736,7 @@
-
+
@@ -3751,7 +3767,7 @@
-
+
@@ -3796,7 +3812,7 @@
-
+